1 /* 2 Defines the basic matrix operations for the AIJ (compressed row) 3 matrix storage format. 4 */ 5 6 #include <../src/mat/impls/aij/seq/aij.h> /*I "petscmat.h" I*/ 7 #include <petscblaslapack.h> 8 #include <petscbt.h> 9 #include <petsc/private/kernels/blocktranspose.h> 10 11 /* defines MatSetValues_Seq_Hash(), MatAssemblyEnd_Seq_Hash(), MatSetUp_Seq_Hash() */ 12 #define TYPE AIJ 13 #define TYPE_BS 14 #include "../src/mat/impls/aij/seq/seqhashmatsetvalues.h" 15 #include "../src/mat/impls/aij/seq/seqhashmat.h" 16 #undef TYPE 17 #undef TYPE_BS 18 19 static PetscErrorCode MatSeqAIJSetTypeFromOptions(Mat A) 20 { 21 PetscBool flg; 22 char type[256]; 23 24 PetscFunctionBegin; 25 PetscObjectOptionsBegin((PetscObject)A); 26 PetscCall(PetscOptionsFList("-mat_seqaij_type", "Matrix SeqAIJ type", "MatSeqAIJSetType", MatSeqAIJList, "seqaij", type, 256, &flg)); 27 if (flg) PetscCall(MatSeqAIJSetType(A, type)); 28 PetscOptionsEnd(); 29 PetscFunctionReturn(PETSC_SUCCESS); 30 } 31 32 static PetscErrorCode MatGetColumnReductions_SeqAIJ(Mat A, PetscInt type, PetscReal *reductions) 33 { 34 PetscInt i, m, n; 35 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 36 37 PetscFunctionBegin; 38 PetscCall(MatGetSize(A, &m, &n)); 39 PetscCall(PetscArrayzero(reductions, n)); 40 if (type == NORM_2) { 41 for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] += PetscAbsScalar(aij->a[i] * aij->a[i]); 42 } else if (type == NORM_1) { 43 for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] += PetscAbsScalar(aij->a[i]); 44 } else if (type == NORM_INFINITY) { 45 for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] = PetscMax(PetscAbsScalar(aij->a[i]), reductions[aij->j[i]]); 46 } else if (type == REDUCTION_SUM_REALPART || type == REDUCTION_MEAN_REALPART) { 47 for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] += PetscRealPart(aij->a[i]); 48 } else if (type == REDUCTION_SUM_IMAGINARYPART || type == REDUCTION_MEAN_IMAGINARYPART) { 49 for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] += PetscImaginaryPart(aij->a[i]); 50 } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Unknown reduction type"); 51 52 if (type == NORM_2) { 53 for (i = 0; i < n; i++) reductions[i] = PetscSqrtReal(reductions[i]); 54 } else if (type == REDUCTION_MEAN_REALPART || type == REDUCTION_MEAN_IMAGINARYPART) { 55 for (i = 0; i < n; i++) reductions[i] /= m; 56 } 57 PetscFunctionReturn(PETSC_SUCCESS); 58 } 59 60 static PetscErrorCode MatFindOffBlockDiagonalEntries_SeqAIJ(Mat A, IS *is) 61 { 62 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 63 PetscInt i, m = A->rmap->n, cnt = 0, bs = A->rmap->bs; 64 const PetscInt *jj = a->j, *ii = a->i; 65 PetscInt *rows; 66 67 PetscFunctionBegin; 68 for (i = 0; i < m; i++) { 69 if ((ii[i] != ii[i + 1]) && ((jj[ii[i]] < bs * (i / bs)) || (jj[ii[i + 1] - 1] > bs * ((i + bs) / bs) - 1))) cnt++; 70 } 71 PetscCall(PetscMalloc1(cnt, &rows)); 72 cnt = 0; 73 for (i = 0; i < m; i++) { 74 if ((ii[i] != ii[i + 1]) && ((jj[ii[i]] < bs * (i / bs)) || (jj[ii[i + 1] - 1] > bs * ((i + bs) / bs) - 1))) { 75 rows[cnt] = i; 76 cnt++; 77 } 78 } 79 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cnt, rows, PETSC_OWN_POINTER, is)); 80 PetscFunctionReturn(PETSC_SUCCESS); 81 } 82 83 PetscErrorCode MatFindZeroDiagonals_SeqAIJ_Private(Mat A, PetscInt *nrows, PetscInt **zrows) 84 { 85 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 86 const MatScalar *aa; 87 PetscInt i, m = A->rmap->n, cnt = 0; 88 const PetscInt *ii = a->i, *jj = a->j, *diag; 89 PetscInt *rows; 90 91 PetscFunctionBegin; 92 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 93 PetscCall(MatMarkDiagonal_SeqAIJ(A)); 94 diag = a->diag; 95 for (i = 0; i < m; i++) { 96 if ((diag[i] >= ii[i + 1]) || (jj[diag[i]] != i) || (aa[diag[i]] == 0.0)) cnt++; 97 } 98 PetscCall(PetscMalloc1(cnt, &rows)); 99 cnt = 0; 100 for (i = 0; i < m; i++) { 101 if ((diag[i] >= ii[i + 1]) || (jj[diag[i]] != i) || (aa[diag[i]] == 0.0)) rows[cnt++] = i; 102 } 103 *nrows = cnt; 104 *zrows = rows; 105 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 106 PetscFunctionReturn(PETSC_SUCCESS); 107 } 108 109 static PetscErrorCode MatFindZeroDiagonals_SeqAIJ(Mat A, IS *zrows) 110 { 111 PetscInt nrows, *rows; 112 113 PetscFunctionBegin; 114 *zrows = NULL; 115 PetscCall(MatFindZeroDiagonals_SeqAIJ_Private(A, &nrows, &rows)); 116 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), nrows, rows, PETSC_OWN_POINTER, zrows)); 117 PetscFunctionReturn(PETSC_SUCCESS); 118 } 119 120 static PetscErrorCode MatFindNonzeroRows_SeqAIJ(Mat A, IS *keptrows) 121 { 122 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 123 const MatScalar *aa; 124 PetscInt m = A->rmap->n, cnt = 0; 125 const PetscInt *ii; 126 PetscInt n, i, j, *rows; 127 128 PetscFunctionBegin; 129 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 130 *keptrows = NULL; 131 ii = a->i; 132 for (i = 0; i < m; i++) { 133 n = ii[i + 1] - ii[i]; 134 if (!n) { 135 cnt++; 136 goto ok1; 137 } 138 for (j = ii[i]; j < ii[i + 1]; j++) { 139 if (aa[j] != 0.0) goto ok1; 140 } 141 cnt++; 142 ok1:; 143 } 144 if (!cnt) { 145 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 146 PetscFunctionReturn(PETSC_SUCCESS); 147 } 148 PetscCall(PetscMalloc1(A->rmap->n - cnt, &rows)); 149 cnt = 0; 150 for (i = 0; i < m; i++) { 151 n = ii[i + 1] - ii[i]; 152 if (!n) continue; 153 for (j = ii[i]; j < ii[i + 1]; j++) { 154 if (aa[j] != 0.0) { 155 rows[cnt++] = i; 156 break; 157 } 158 } 159 } 160 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 161 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cnt, rows, PETSC_OWN_POINTER, keptrows)); 162 PetscFunctionReturn(PETSC_SUCCESS); 163 } 164 165 PetscErrorCode MatDiagonalSet_SeqAIJ(Mat Y, Vec D, InsertMode is) 166 { 167 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)Y->data; 168 PetscInt i, m = Y->rmap->n; 169 const PetscInt *diag; 170 MatScalar *aa; 171 const PetscScalar *v; 172 PetscBool missing; 173 174 PetscFunctionBegin; 175 if (Y->assembled) { 176 PetscCall(MatMissingDiagonal_SeqAIJ(Y, &missing, NULL)); 177 if (!missing) { 178 diag = aij->diag; 179 PetscCall(VecGetArrayRead(D, &v)); 180 PetscCall(MatSeqAIJGetArray(Y, &aa)); 181 if (is == INSERT_VALUES) { 182 for (i = 0; i < m; i++) aa[diag[i]] = v[i]; 183 } else { 184 for (i = 0; i < m; i++) aa[diag[i]] += v[i]; 185 } 186 PetscCall(MatSeqAIJRestoreArray(Y, &aa)); 187 PetscCall(VecRestoreArrayRead(D, &v)); 188 PetscFunctionReturn(PETSC_SUCCESS); 189 } 190 PetscCall(MatSeqAIJInvalidateDiagonal(Y)); 191 } 192 PetscCall(MatDiagonalSet_Default(Y, D, is)); 193 PetscFunctionReturn(PETSC_SUCCESS); 194 } 195 196 PetscErrorCode MatGetRowIJ_SeqAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *m, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done) 197 { 198 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 199 PetscInt i, ishift; 200 201 PetscFunctionBegin; 202 if (m) *m = A->rmap->n; 203 if (!ia) PetscFunctionReturn(PETSC_SUCCESS); 204 ishift = 0; 205 if (symmetric && A->structurally_symmetric != PETSC_BOOL3_TRUE) { 206 PetscCall(MatToSymmetricIJ_SeqAIJ(A->rmap->n, a->i, a->j, PETSC_TRUE, ishift, oshift, (PetscInt **)ia, (PetscInt **)ja)); 207 } else if (oshift == 1) { 208 PetscInt *tia; 209 PetscInt nz = a->i[A->rmap->n]; 210 /* malloc space and add 1 to i and j indices */ 211 PetscCall(PetscMalloc1(A->rmap->n + 1, &tia)); 212 for (i = 0; i < A->rmap->n + 1; i++) tia[i] = a->i[i] + 1; 213 *ia = tia; 214 if (ja) { 215 PetscInt *tja; 216 PetscCall(PetscMalloc1(nz + 1, &tja)); 217 for (i = 0; i < nz; i++) tja[i] = a->j[i] + 1; 218 *ja = tja; 219 } 220 } else { 221 *ia = a->i; 222 if (ja) *ja = a->j; 223 } 224 PetscFunctionReturn(PETSC_SUCCESS); 225 } 226 227 PetscErrorCode MatRestoreRowIJ_SeqAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done) 228 { 229 PetscFunctionBegin; 230 if (!ia) PetscFunctionReturn(PETSC_SUCCESS); 231 if ((symmetric && A->structurally_symmetric != PETSC_BOOL3_TRUE) || oshift == 1) { 232 PetscCall(PetscFree(*ia)); 233 if (ja) PetscCall(PetscFree(*ja)); 234 } 235 PetscFunctionReturn(PETSC_SUCCESS); 236 } 237 238 PetscErrorCode MatGetColumnIJ_SeqAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *nn, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done) 239 { 240 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 241 PetscInt i, *collengths, *cia, *cja, n = A->cmap->n, m = A->rmap->n; 242 PetscInt nz = a->i[m], row, *jj, mr, col; 243 244 PetscFunctionBegin; 245 *nn = n; 246 if (!ia) PetscFunctionReturn(PETSC_SUCCESS); 247 if (symmetric) { 248 PetscCall(MatToSymmetricIJ_SeqAIJ(A->rmap->n, a->i, a->j, PETSC_TRUE, 0, oshift, (PetscInt **)ia, (PetscInt **)ja)); 249 } else { 250 PetscCall(PetscCalloc1(n, &collengths)); 251 PetscCall(PetscMalloc1(n + 1, &cia)); 252 PetscCall(PetscMalloc1(nz, &cja)); 253 jj = a->j; 254 for (i = 0; i < nz; i++) collengths[jj[i]]++; 255 cia[0] = oshift; 256 for (i = 0; i < n; i++) cia[i + 1] = cia[i] + collengths[i]; 257 PetscCall(PetscArrayzero(collengths, n)); 258 jj = a->j; 259 for (row = 0; row < m; row++) { 260 mr = a->i[row + 1] - a->i[row]; 261 for (i = 0; i < mr; i++) { 262 col = *jj++; 263 264 cja[cia[col] + collengths[col]++ - oshift] = row + oshift; 265 } 266 } 267 PetscCall(PetscFree(collengths)); 268 *ia = cia; 269 *ja = cja; 270 } 271 PetscFunctionReturn(PETSC_SUCCESS); 272 } 273 274 PetscErrorCode MatRestoreColumnIJ_SeqAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done) 275 { 276 PetscFunctionBegin; 277 if (!ia) PetscFunctionReturn(PETSC_SUCCESS); 278 279 PetscCall(PetscFree(*ia)); 280 PetscCall(PetscFree(*ja)); 281 PetscFunctionReturn(PETSC_SUCCESS); 282 } 283 284 /* 285 MatGetColumnIJ_SeqAIJ_Color() and MatRestoreColumnIJ_SeqAIJ_Color() are customized from 286 MatGetColumnIJ_SeqAIJ() and MatRestoreColumnIJ_SeqAIJ() by adding an output 287 spidx[], index of a->a, to be used in MatTransposeColoringCreate_SeqAIJ() and MatFDColoringCreate_SeqXAIJ() 288 */ 289 PetscErrorCode MatGetColumnIJ_SeqAIJ_Color(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *nn, const PetscInt *ia[], const PetscInt *ja[], PetscInt *spidx[], PetscBool *done) 290 { 291 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 292 PetscInt i, *collengths, *cia, *cja, n = A->cmap->n, m = A->rmap->n; 293 PetscInt nz = a->i[m], row, mr, col, tmp; 294 PetscInt *cspidx; 295 const PetscInt *jj; 296 297 PetscFunctionBegin; 298 *nn = n; 299 if (!ia) PetscFunctionReturn(PETSC_SUCCESS); 300 301 PetscCall(PetscCalloc1(n, &collengths)); 302 PetscCall(PetscMalloc1(n + 1, &cia)); 303 PetscCall(PetscMalloc1(nz, &cja)); 304 PetscCall(PetscMalloc1(nz, &cspidx)); 305 jj = a->j; 306 for (i = 0; i < nz; i++) collengths[jj[i]]++; 307 cia[0] = oshift; 308 for (i = 0; i < n; i++) cia[i + 1] = cia[i] + collengths[i]; 309 PetscCall(PetscArrayzero(collengths, n)); 310 jj = a->j; 311 for (row = 0; row < m; row++) { 312 mr = a->i[row + 1] - a->i[row]; 313 for (i = 0; i < mr; i++) { 314 col = *jj++; 315 tmp = cia[col] + collengths[col]++ - oshift; 316 cspidx[tmp] = a->i[row] + i; /* index of a->j */ 317 cja[tmp] = row + oshift; 318 } 319 } 320 PetscCall(PetscFree(collengths)); 321 *ia = cia; 322 *ja = cja; 323 *spidx = cspidx; 324 PetscFunctionReturn(PETSC_SUCCESS); 325 } 326 327 PetscErrorCode MatRestoreColumnIJ_SeqAIJ_Color(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscInt *spidx[], PetscBool *done) 328 { 329 PetscFunctionBegin; 330 PetscCall(MatRestoreColumnIJ_SeqAIJ(A, oshift, symmetric, inodecompressed, n, ia, ja, done)); 331 PetscCall(PetscFree(*spidx)); 332 PetscFunctionReturn(PETSC_SUCCESS); 333 } 334 335 static PetscErrorCode MatSetValuesRow_SeqAIJ(Mat A, PetscInt row, const PetscScalar v[]) 336 { 337 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 338 PetscInt *ai = a->i; 339 PetscScalar *aa; 340 341 PetscFunctionBegin; 342 PetscCall(MatSeqAIJGetArray(A, &aa)); 343 PetscCall(PetscArraycpy(aa + ai[row], v, ai[row + 1] - ai[row])); 344 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 345 PetscFunctionReturn(PETSC_SUCCESS); 346 } 347 348 /* 349 MatSeqAIJSetValuesLocalFast - An optimized version of MatSetValuesLocal() for SeqAIJ matrices with several assumptions 350 351 - a single row of values is set with each call 352 - no row or column indices are negative or (in error) larger than the number of rows or columns 353 - the values are always added to the matrix, not set 354 - no new locations are introduced in the nonzero structure of the matrix 355 356 This does NOT assume the global column indices are sorted 357 358 */ 359 360 #include <petsc/private/isimpl.h> 361 PetscErrorCode MatSeqAIJSetValuesLocalFast(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is) 362 { 363 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 364 PetscInt low, high, t, row, nrow, i, col, l; 365 const PetscInt *rp, *ai = a->i, *ailen = a->ilen, *aj = a->j; 366 PetscInt lastcol = -1; 367 MatScalar *ap, value, *aa; 368 const PetscInt *ridx = A->rmap->mapping->indices, *cidx = A->cmap->mapping->indices; 369 370 PetscFunctionBegin; 371 PetscCall(MatSeqAIJGetArray(A, &aa)); 372 row = ridx[im[0]]; 373 rp = aj + ai[row]; 374 ap = aa + ai[row]; 375 nrow = ailen[row]; 376 low = 0; 377 high = nrow; 378 for (l = 0; l < n; l++) { /* loop over added columns */ 379 col = cidx[in[l]]; 380 value = v[l]; 381 382 if (col <= lastcol) low = 0; 383 else high = nrow; 384 lastcol = col; 385 while (high - low > 5) { 386 t = (low + high) / 2; 387 if (rp[t] > col) high = t; 388 else low = t; 389 } 390 for (i = low; i < high; i++) { 391 if (rp[i] == col) { 392 ap[i] += value; 393 low = i + 1; 394 break; 395 } 396 } 397 } 398 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 399 return PETSC_SUCCESS; 400 } 401 402 PetscErrorCode MatSetValues_SeqAIJ(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is) 403 { 404 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 405 PetscInt *rp, k, low, high, t, ii, row, nrow, i, col, l, rmax, N; 406 PetscInt *imax = a->imax, *ai = a->i, *ailen = a->ilen; 407 PetscInt *aj = a->j, nonew = a->nonew, lastcol = -1; 408 MatScalar *ap = NULL, value = 0.0, *aa; 409 PetscBool ignorezeroentries = a->ignorezeroentries; 410 PetscBool roworiented = a->roworiented; 411 412 PetscFunctionBegin; 413 PetscCall(MatSeqAIJGetArray(A, &aa)); 414 for (k = 0; k < m; k++) { /* loop over added rows */ 415 row = im[k]; 416 if (row < 0) continue; 417 PetscCheck(row < A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, row, A->rmap->n - 1); 418 rp = PetscSafePointerPlusOffset(aj, ai[row]); 419 if (!A->structure_only) ap = PetscSafePointerPlusOffset(aa, ai[row]); 420 rmax = imax[row]; 421 nrow = ailen[row]; 422 low = 0; 423 high = nrow; 424 for (l = 0; l < n; l++) { /* loop over added columns */ 425 if (in[l] < 0) continue; 426 PetscCheck(in[l] < A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column too large: col %" PetscInt_FMT " max %" PetscInt_FMT, in[l], A->cmap->n - 1); 427 col = in[l]; 428 if (v && !A->structure_only) value = roworiented ? v[l + k * n] : v[k + l * m]; 429 if (!A->structure_only && value == 0.0 && ignorezeroentries && is == ADD_VALUES && row != col) continue; 430 431 if (col <= lastcol) low = 0; 432 else high = nrow; 433 lastcol = col; 434 while (high - low > 5) { 435 t = (low + high) / 2; 436 if (rp[t] > col) high = t; 437 else low = t; 438 } 439 for (i = low; i < high; i++) { 440 if (rp[i] > col) break; 441 if (rp[i] == col) { 442 if (!A->structure_only) { 443 if (is == ADD_VALUES) { 444 ap[i] += value; 445 (void)PetscLogFlops(1.0); 446 } else ap[i] = value; 447 } 448 low = i + 1; 449 goto noinsert; 450 } 451 } 452 if (value == 0.0 && ignorezeroentries && row != col) goto noinsert; 453 if (nonew == 1) goto noinsert; 454 PetscCheck(nonew != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero at (%" PetscInt_FMT ",%" PetscInt_FMT ") in the matrix", row, col); 455 if (A->structure_only) { 456 MatSeqXAIJReallocateAIJ_structure_only(A, A->rmap->n, 1, nrow, row, col, rmax, ai, aj, rp, imax, nonew, MatScalar); 457 } else { 458 MatSeqXAIJReallocateAIJ(A, A->rmap->n, 1, nrow, row, col, rmax, aa, ai, aj, rp, ap, imax, nonew, MatScalar); 459 } 460 N = nrow++ - 1; 461 a->nz++; 462 high++; 463 /* shift up all the later entries in this row */ 464 PetscCall(PetscArraymove(rp + i + 1, rp + i, N - i + 1)); 465 rp[i] = col; 466 if (!A->structure_only) { 467 PetscCall(PetscArraymove(ap + i + 1, ap + i, N - i + 1)); 468 ap[i] = value; 469 } 470 low = i + 1; 471 noinsert:; 472 } 473 ailen[row] = nrow; 474 } 475 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 476 PetscFunctionReturn(PETSC_SUCCESS); 477 } 478 479 static PetscErrorCode MatSetValues_SeqAIJ_SortedFullNoPreallocation(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is) 480 { 481 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 482 PetscInt *rp, k, row; 483 PetscInt *ai = a->i; 484 PetscInt *aj = a->j; 485 MatScalar *aa, *ap; 486 487 PetscFunctionBegin; 488 PetscCheck(!A->was_assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot call on assembled matrix."); 489 PetscCheck(m * n + a->nz <= a->maxnz, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of entries in matrix will be larger than maximum nonzeros allocated for %" PetscInt_FMT " in MatSeqAIJSetTotalPreallocation()", a->maxnz); 490 491 PetscCall(MatSeqAIJGetArray(A, &aa)); 492 for (k = 0; k < m; k++) { /* loop over added rows */ 493 row = im[k]; 494 rp = aj + ai[row]; 495 ap = PetscSafePointerPlusOffset(aa, ai[row]); 496 497 PetscCall(PetscMemcpy(rp, in, n * sizeof(PetscInt))); 498 if (!A->structure_only) { 499 if (v) { 500 PetscCall(PetscMemcpy(ap, v, n * sizeof(PetscScalar))); 501 v += n; 502 } else { 503 PetscCall(PetscMemzero(ap, n * sizeof(PetscScalar))); 504 } 505 } 506 a->ilen[row] = n; 507 a->imax[row] = n; 508 a->i[row + 1] = a->i[row] + n; 509 a->nz += n; 510 } 511 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 512 PetscFunctionReturn(PETSC_SUCCESS); 513 } 514 515 /*@ 516 MatSeqAIJSetTotalPreallocation - Sets an upper bound on the total number of expected nonzeros in the matrix. 517 518 Input Parameters: 519 + A - the `MATSEQAIJ` matrix 520 - nztotal - bound on the number of nonzeros 521 522 Level: advanced 523 524 Notes: 525 This can be called if you will be provided the matrix row by row (from row zero) with sorted column indices for each row. 526 Simply call `MatSetValues()` after this call to provide the matrix entries in the usual manner. This matrix may be used 527 as always with multiple matrix assemblies. 528 529 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MAT_SORTED_FULL`, `MatSetValues()`, `MatSeqAIJSetPreallocation()` 530 @*/ 531 PetscErrorCode MatSeqAIJSetTotalPreallocation(Mat A, PetscInt nztotal) 532 { 533 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 534 535 PetscFunctionBegin; 536 PetscCall(PetscLayoutSetUp(A->rmap)); 537 PetscCall(PetscLayoutSetUp(A->cmap)); 538 a->maxnz = nztotal; 539 if (!a->imax) { PetscCall(PetscMalloc1(A->rmap->n, &a->imax)); } 540 if (!a->ilen) { 541 PetscCall(PetscMalloc1(A->rmap->n, &a->ilen)); 542 } else { 543 PetscCall(PetscMemzero(a->ilen, A->rmap->n * sizeof(PetscInt))); 544 } 545 546 /* allocate the matrix space */ 547 PetscCall(PetscShmgetAllocateArray(A->rmap->n + 1, sizeof(PetscInt), (void **)&a->i)); 548 PetscCall(PetscShmgetAllocateArray(nztotal, sizeof(PetscInt), (void **)&a->j)); 549 a->free_ij = PETSC_TRUE; 550 if (A->structure_only) { 551 a->free_a = PETSC_FALSE; 552 } else { 553 PetscCall(PetscShmgetAllocateArray(nztotal, sizeof(PetscScalar), (void **)&a->a)); 554 a->free_a = PETSC_TRUE; 555 } 556 a->i[0] = 0; 557 A->ops->setvalues = MatSetValues_SeqAIJ_SortedFullNoPreallocation; 558 A->preallocated = PETSC_TRUE; 559 PetscFunctionReturn(PETSC_SUCCESS); 560 } 561 562 static PetscErrorCode MatSetValues_SeqAIJ_SortedFull(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is) 563 { 564 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 565 PetscInt *rp, k, row; 566 PetscInt *ai = a->i, *ailen = a->ilen; 567 PetscInt *aj = a->j; 568 MatScalar *aa, *ap; 569 570 PetscFunctionBegin; 571 PetscCall(MatSeqAIJGetArray(A, &aa)); 572 for (k = 0; k < m; k++) { /* loop over added rows */ 573 row = im[k]; 574 PetscCheck(n <= a->imax[row], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Preallocation for row %" PetscInt_FMT " does not match number of columns provided", n); 575 rp = aj + ai[row]; 576 ap = aa + ai[row]; 577 if (!A->was_assembled) PetscCall(PetscMemcpy(rp, in, n * sizeof(PetscInt))); 578 if (!A->structure_only) { 579 if (v) { 580 PetscCall(PetscMemcpy(ap, v, n * sizeof(PetscScalar))); 581 v += n; 582 } else { 583 PetscCall(PetscMemzero(ap, n * sizeof(PetscScalar))); 584 } 585 } 586 ailen[row] = n; 587 a->nz += n; 588 } 589 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 590 PetscFunctionReturn(PETSC_SUCCESS); 591 } 592 593 static PetscErrorCode MatGetValues_SeqAIJ(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], PetscScalar v[]) 594 { 595 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 596 PetscInt *rp, k, low, high, t, row, nrow, i, col, l, *aj = a->j; 597 PetscInt *ai = a->i, *ailen = a->ilen; 598 const MatScalar *ap, *aa; 599 600 PetscFunctionBegin; 601 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 602 for (k = 0; k < m; k++) { /* loop over rows */ 603 row = im[k]; 604 if (row < 0) { 605 v += n; 606 continue; 607 } /* negative row */ 608 PetscCheck(row < A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, row, A->rmap->n - 1); 609 rp = PetscSafePointerPlusOffset(aj, ai[row]); 610 ap = PetscSafePointerPlusOffset(aa, ai[row]); 611 nrow = ailen[row]; 612 for (l = 0; l < n; l++) { /* loop over columns */ 613 if (in[l] < 0) { 614 v++; 615 continue; 616 } /* negative column */ 617 PetscCheck(in[l] < A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column too large: col %" PetscInt_FMT " max %" PetscInt_FMT, in[l], A->cmap->n - 1); 618 col = in[l]; 619 high = nrow; 620 low = 0; /* assume unsorted */ 621 while (high - low > 5) { 622 t = (low + high) / 2; 623 if (rp[t] > col) high = t; 624 else low = t; 625 } 626 for (i = low; i < high; i++) { 627 if (rp[i] > col) break; 628 if (rp[i] == col) { 629 *v++ = ap[i]; 630 goto finished; 631 } 632 } 633 *v++ = 0.0; 634 finished:; 635 } 636 } 637 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 638 PetscFunctionReturn(PETSC_SUCCESS); 639 } 640 641 static PetscErrorCode MatView_SeqAIJ_Binary(Mat mat, PetscViewer viewer) 642 { 643 Mat_SeqAIJ *A = (Mat_SeqAIJ *)mat->data; 644 const PetscScalar *av; 645 PetscInt header[4], M, N, m, nz, i; 646 PetscInt *rowlens; 647 648 PetscFunctionBegin; 649 PetscCall(PetscViewerSetUp(viewer)); 650 651 M = mat->rmap->N; 652 N = mat->cmap->N; 653 m = mat->rmap->n; 654 nz = A->nz; 655 656 /* write matrix header */ 657 header[0] = MAT_FILE_CLASSID; 658 header[1] = M; 659 header[2] = N; 660 header[3] = nz; 661 PetscCall(PetscViewerBinaryWrite(viewer, header, 4, PETSC_INT)); 662 663 /* fill in and store row lengths */ 664 PetscCall(PetscMalloc1(m, &rowlens)); 665 for (i = 0; i < m; i++) rowlens[i] = A->i[i + 1] - A->i[i]; 666 if (PetscDefined(USE_DEBUG)) { 667 PetscInt mnz = 0; 668 669 for (i = 0; i < m; i++) mnz += rowlens[i]; 670 PetscCheck(nz == mnz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Row lens %" PetscInt_FMT " do not sum to nz %" PetscInt_FMT, mnz, nz); 671 } 672 PetscCall(PetscViewerBinaryWrite(viewer, rowlens, m, PETSC_INT)); 673 PetscCall(PetscFree(rowlens)); 674 /* store column indices */ 675 PetscCall(PetscViewerBinaryWrite(viewer, A->j, nz, PETSC_INT)); 676 /* store nonzero values */ 677 PetscCall(MatSeqAIJGetArrayRead(mat, &av)); 678 PetscCall(PetscViewerBinaryWrite(viewer, av, nz, PETSC_SCALAR)); 679 PetscCall(MatSeqAIJRestoreArrayRead(mat, &av)); 680 681 /* write block size option to the viewer's .info file */ 682 PetscCall(MatView_Binary_BlockSizes(mat, viewer)); 683 PetscFunctionReturn(PETSC_SUCCESS); 684 } 685 686 static PetscErrorCode MatView_SeqAIJ_ASCII_structonly(Mat A, PetscViewer viewer) 687 { 688 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 689 PetscInt i, k, m = A->rmap->N; 690 691 PetscFunctionBegin; 692 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 693 for (i = 0; i < m; i++) { 694 PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i)); 695 for (k = a->i[i]; k < a->i[i + 1]; k++) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ") ", a->j[k])); 696 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 697 } 698 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 699 PetscFunctionReturn(PETSC_SUCCESS); 700 } 701 702 static PetscErrorCode MatView_SeqAIJ_ASCII(Mat A, PetscViewer viewer) 703 { 704 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 705 const PetscScalar *av; 706 PetscInt i, j, m = A->rmap->n; 707 const char *name; 708 PetscViewerFormat format; 709 710 PetscFunctionBegin; 711 if (A->structure_only) { 712 PetscCall(MatView_SeqAIJ_ASCII_structonly(A, viewer)); 713 PetscFunctionReturn(PETSC_SUCCESS); 714 } 715 716 PetscCall(PetscViewerGetFormat(viewer, &format)); 717 // By petsc's rule, even PETSC_VIEWER_ASCII_INFO_DETAIL doesn't print matrix entries 718 if (format == PETSC_VIEWER_ASCII_FACTOR_INFO || format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) PetscFunctionReturn(PETSC_SUCCESS); 719 720 /* trigger copy to CPU if needed */ 721 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 722 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 723 if (format == PETSC_VIEWER_ASCII_MATLAB) { 724 PetscInt nofinalvalue = 0; 725 if (m && ((a->i[m] == a->i[m - 1]) || (a->j[a->nz - 1] != A->cmap->n - 1))) { 726 /* Need a dummy value to ensure the dimension of the matrix. */ 727 nofinalvalue = 1; 728 } 729 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 730 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Size = %" PetscInt_FMT " %" PetscInt_FMT " \n", m, A->cmap->n)); 731 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Nonzeros = %" PetscInt_FMT " \n", a->nz)); 732 #if defined(PETSC_USE_COMPLEX) 733 PetscCall(PetscViewerASCIIPrintf(viewer, "zzz = zeros(%" PetscInt_FMT ",4);\n", a->nz + nofinalvalue)); 734 #else 735 PetscCall(PetscViewerASCIIPrintf(viewer, "zzz = zeros(%" PetscInt_FMT ",3);\n", a->nz + nofinalvalue)); 736 #endif 737 PetscCall(PetscViewerASCIIPrintf(viewer, "zzz = [\n")); 738 739 for (i = 0; i < m; i++) { 740 for (j = a->i[i]; j < a->i[i + 1]; j++) { 741 #if defined(PETSC_USE_COMPLEX) 742 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %18.16e %18.16e\n", i + 1, a->j[j] + 1, (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 743 #else 744 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %18.16e\n", i + 1, a->j[j] + 1, (double)a->a[j])); 745 #endif 746 } 747 } 748 if (nofinalvalue) { 749 #if defined(PETSC_USE_COMPLEX) 750 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %18.16e %18.16e\n", m, A->cmap->n, 0., 0.)); 751 #else 752 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %18.16e\n", m, A->cmap->n, 0.0)); 753 #endif 754 } 755 PetscCall(PetscObjectGetName((PetscObject)A, &name)); 756 PetscCall(PetscViewerASCIIPrintf(viewer, "];\n %s = spconvert(zzz);\n", name)); 757 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 758 } else if (format == PETSC_VIEWER_ASCII_COMMON) { 759 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 760 for (i = 0; i < m; i++) { 761 PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i)); 762 for (j = a->i[i]; j < a->i[i + 1]; j++) { 763 #if defined(PETSC_USE_COMPLEX) 764 if (PetscImaginaryPart(a->a[j]) > 0.0 && PetscRealPart(a->a[j]) != 0.0) { 765 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 766 } else if (PetscImaginaryPart(a->a[j]) < 0.0 && PetscRealPart(a->a[j]) != 0.0) { 767 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)-PetscImaginaryPart(a->a[j]))); 768 } else if (PetscRealPart(a->a[j]) != 0.0) { 769 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(a->a[j]))); 770 } 771 #else 772 if (a->a[j] != 0.0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)a->a[j])); 773 #endif 774 } 775 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 776 } 777 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 778 } else if (format == PETSC_VIEWER_ASCII_SYMMODU) { 779 PetscInt nzd = 0, fshift = 1, *sptr; 780 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 781 PetscCall(PetscMalloc1(m + 1, &sptr)); 782 for (i = 0; i < m; i++) { 783 sptr[i] = nzd + 1; 784 for (j = a->i[i]; j < a->i[i + 1]; j++) { 785 if (a->j[j] >= i) { 786 #if defined(PETSC_USE_COMPLEX) 787 if (PetscImaginaryPart(a->a[j]) != 0.0 || PetscRealPart(a->a[j]) != 0.0) nzd++; 788 #else 789 if (a->a[j] != 0.0) nzd++; 790 #endif 791 } 792 } 793 } 794 sptr[m] = nzd + 1; 795 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT "\n\n", m, nzd)); 796 for (i = 0; i < m + 1; i += 6) { 797 if (i + 4 < m) { 798 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1], sptr[i + 2], sptr[i + 3], sptr[i + 4], sptr[i + 5])); 799 } else if (i + 3 < m) { 800 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1], sptr[i + 2], sptr[i + 3], sptr[i + 4])); 801 } else if (i + 2 < m) { 802 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1], sptr[i + 2], sptr[i + 3])); 803 } else if (i + 1 < m) { 804 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1], sptr[i + 2])); 805 } else if (i < m) { 806 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1])); 807 } else { 808 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "\n", sptr[i])); 809 } 810 } 811 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 812 PetscCall(PetscFree(sptr)); 813 for (i = 0; i < m; i++) { 814 for (j = a->i[i]; j < a->i[i + 1]; j++) { 815 if (a->j[j] >= i) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " ", a->j[j] + fshift)); 816 } 817 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 818 } 819 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 820 for (i = 0; i < m; i++) { 821 for (j = a->i[i]; j < a->i[i + 1]; j++) { 822 if (a->j[j] >= i) { 823 #if defined(PETSC_USE_COMPLEX) 824 if (PetscImaginaryPart(a->a[j]) != 0.0 || PetscRealPart(a->a[j]) != 0.0) PetscCall(PetscViewerASCIIPrintf(viewer, " %18.16e %18.16e ", (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 825 #else 826 if (a->a[j] != 0.0) PetscCall(PetscViewerASCIIPrintf(viewer, " %18.16e ", (double)a->a[j])); 827 #endif 828 } 829 } 830 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 831 } 832 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 833 } else if (format == PETSC_VIEWER_ASCII_DENSE) { 834 PetscInt cnt = 0, jcnt; 835 PetscScalar value; 836 #if defined(PETSC_USE_COMPLEX) 837 PetscBool realonly = PETSC_TRUE; 838 839 for (i = 0; i < a->i[m]; i++) { 840 if (PetscImaginaryPart(a->a[i]) != 0.0) { 841 realonly = PETSC_FALSE; 842 break; 843 } 844 } 845 #endif 846 847 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 848 for (i = 0; i < m; i++) { 849 jcnt = 0; 850 for (j = 0; j < A->cmap->n; j++) { 851 if (jcnt < a->i[i + 1] - a->i[i] && j == a->j[cnt]) { 852 value = a->a[cnt++]; 853 jcnt++; 854 } else { 855 value = 0.0; 856 } 857 #if defined(PETSC_USE_COMPLEX) 858 if (realonly) { 859 PetscCall(PetscViewerASCIIPrintf(viewer, " %7.5e ", (double)PetscRealPart(value))); 860 } else { 861 PetscCall(PetscViewerASCIIPrintf(viewer, " %7.5e+%7.5e i ", (double)PetscRealPart(value), (double)PetscImaginaryPart(value))); 862 } 863 #else 864 PetscCall(PetscViewerASCIIPrintf(viewer, " %7.5e ", (double)value)); 865 #endif 866 } 867 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 868 } 869 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 870 } else if (format == PETSC_VIEWER_ASCII_MATRIXMARKET) { 871 PetscInt fshift = 1; 872 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 873 #if defined(PETSC_USE_COMPLEX) 874 PetscCall(PetscViewerASCIIPrintf(viewer, "%%%%MatrixMarket matrix coordinate complex general\n")); 875 #else 876 PetscCall(PetscViewerASCIIPrintf(viewer, "%%%%MatrixMarket matrix coordinate real general\n")); 877 #endif 878 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", m, A->cmap->n, a->nz)); 879 for (i = 0; i < m; i++) { 880 for (j = a->i[i]; j < a->i[i + 1]; j++) { 881 #if defined(PETSC_USE_COMPLEX) 882 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %g %g\n", i + fshift, a->j[j] + fshift, (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 883 #else 884 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %g\n", i + fshift, a->j[j] + fshift, (double)a->a[j])); 885 #endif 886 } 887 } 888 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 889 } else { 890 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 891 if (A->factortype) { 892 for (i = 0; i < m; i++) { 893 PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i)); 894 /* L part */ 895 for (j = a->i[i]; j < a->i[i + 1]; j++) { 896 #if defined(PETSC_USE_COMPLEX) 897 if (PetscImaginaryPart(a->a[j]) > 0.0) { 898 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 899 } else if (PetscImaginaryPart(a->a[j]) < 0.0) { 900 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)(-PetscImaginaryPart(a->a[j])))); 901 } else { 902 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(a->a[j]))); 903 } 904 #else 905 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)a->a[j])); 906 #endif 907 } 908 /* diagonal */ 909 j = a->diag[i]; 910 #if defined(PETSC_USE_COMPLEX) 911 if (PetscImaginaryPart(a->a[j]) > 0.0) { 912 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(1 / a->a[j]), (double)PetscImaginaryPart(1 / a->a[j]))); 913 } else if (PetscImaginaryPart(a->a[j]) < 0.0) { 914 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(1 / a->a[j]), (double)(-PetscImaginaryPart(1 / a->a[j])))); 915 } else { 916 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(1 / a->a[j]))); 917 } 918 #else 919 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)(1 / a->a[j]))); 920 #endif 921 922 /* U part */ 923 for (j = a->diag[i + 1] + 1; j < a->diag[i]; j++) { 924 #if defined(PETSC_USE_COMPLEX) 925 if (PetscImaginaryPart(a->a[j]) > 0.0) { 926 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 927 } else if (PetscImaginaryPart(a->a[j]) < 0.0) { 928 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)(-PetscImaginaryPart(a->a[j])))); 929 } else { 930 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(a->a[j]))); 931 } 932 #else 933 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)a->a[j])); 934 #endif 935 } 936 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 937 } 938 } else { 939 for (i = 0; i < m; i++) { 940 PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i)); 941 for (j = a->i[i]; j < a->i[i + 1]; j++) { 942 #if defined(PETSC_USE_COMPLEX) 943 if (PetscImaginaryPart(a->a[j]) > 0.0) { 944 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 945 } else if (PetscImaginaryPart(a->a[j]) < 0.0) { 946 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)-PetscImaginaryPart(a->a[j]))); 947 } else { 948 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(a->a[j]))); 949 } 950 #else 951 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)a->a[j])); 952 #endif 953 } 954 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 955 } 956 } 957 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 958 } 959 PetscCall(PetscViewerFlush(viewer)); 960 PetscFunctionReturn(PETSC_SUCCESS); 961 } 962 963 #include <petscdraw.h> 964 static PetscErrorCode MatView_SeqAIJ_Draw_Zoom(PetscDraw draw, void *Aa) 965 { 966 Mat A = (Mat)Aa; 967 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 968 PetscInt i, j, m = A->rmap->n; 969 int color; 970 PetscReal xl, yl, xr, yr, x_l, x_r, y_l, y_r; 971 PetscViewer viewer; 972 PetscViewerFormat format; 973 const PetscScalar *aa; 974 975 PetscFunctionBegin; 976 PetscCall(PetscObjectQuery((PetscObject)A, "Zoomviewer", (PetscObject *)&viewer)); 977 PetscCall(PetscViewerGetFormat(viewer, &format)); 978 PetscCall(PetscDrawGetCoordinates(draw, &xl, &yl, &xr, &yr)); 979 980 /* loop over matrix elements drawing boxes */ 981 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 982 if (format != PETSC_VIEWER_DRAW_CONTOUR) { 983 PetscDrawCollectiveBegin(draw); 984 /* Blue for negative, Cyan for zero and Red for positive */ 985 color = PETSC_DRAW_BLUE; 986 for (i = 0; i < m; i++) { 987 y_l = m - i - 1.0; 988 y_r = y_l + 1.0; 989 for (j = a->i[i]; j < a->i[i + 1]; j++) { 990 x_l = a->j[j]; 991 x_r = x_l + 1.0; 992 if (PetscRealPart(aa[j]) >= 0.) continue; 993 PetscCall(PetscDrawRectangle(draw, x_l, y_l, x_r, y_r, color, color, color, color)); 994 } 995 } 996 color = PETSC_DRAW_CYAN; 997 for (i = 0; i < m; i++) { 998 y_l = m - i - 1.0; 999 y_r = y_l + 1.0; 1000 for (j = a->i[i]; j < a->i[i + 1]; j++) { 1001 x_l = a->j[j]; 1002 x_r = x_l + 1.0; 1003 if (aa[j] != 0.) continue; 1004 PetscCall(PetscDrawRectangle(draw, x_l, y_l, x_r, y_r, color, color, color, color)); 1005 } 1006 } 1007 color = PETSC_DRAW_RED; 1008 for (i = 0; i < m; i++) { 1009 y_l = m - i - 1.0; 1010 y_r = y_l + 1.0; 1011 for (j = a->i[i]; j < a->i[i + 1]; j++) { 1012 x_l = a->j[j]; 1013 x_r = x_l + 1.0; 1014 if (PetscRealPart(aa[j]) <= 0.) continue; 1015 PetscCall(PetscDrawRectangle(draw, x_l, y_l, x_r, y_r, color, color, color, color)); 1016 } 1017 } 1018 PetscDrawCollectiveEnd(draw); 1019 } else { 1020 /* use contour shading to indicate magnitude of values */ 1021 /* first determine max of all nonzero values */ 1022 PetscReal minv = 0.0, maxv = 0.0; 1023 PetscInt nz = a->nz, count = 0; 1024 PetscDraw popup; 1025 1026 for (i = 0; i < nz; i++) { 1027 if (PetscAbsScalar(aa[i]) > maxv) maxv = PetscAbsScalar(aa[i]); 1028 } 1029 if (minv >= maxv) maxv = minv + PETSC_SMALL; 1030 PetscCall(PetscDrawGetPopup(draw, &popup)); 1031 PetscCall(PetscDrawScalePopup(popup, minv, maxv)); 1032 1033 PetscDrawCollectiveBegin(draw); 1034 for (i = 0; i < m; i++) { 1035 y_l = m - i - 1.0; 1036 y_r = y_l + 1.0; 1037 for (j = a->i[i]; j < a->i[i + 1]; j++) { 1038 x_l = a->j[j]; 1039 x_r = x_l + 1.0; 1040 color = PetscDrawRealToColor(PetscAbsScalar(aa[count]), minv, maxv); 1041 PetscCall(PetscDrawRectangle(draw, x_l, y_l, x_r, y_r, color, color, color, color)); 1042 count++; 1043 } 1044 } 1045 PetscDrawCollectiveEnd(draw); 1046 } 1047 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 1048 PetscFunctionReturn(PETSC_SUCCESS); 1049 } 1050 1051 #include <petscdraw.h> 1052 static PetscErrorCode MatView_SeqAIJ_Draw(Mat A, PetscViewer viewer) 1053 { 1054 PetscDraw draw; 1055 PetscReal xr, yr, xl, yl, h, w; 1056 PetscBool isnull; 1057 1058 PetscFunctionBegin; 1059 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1060 PetscCall(PetscDrawIsNull(draw, &isnull)); 1061 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1062 1063 xr = A->cmap->n; 1064 yr = A->rmap->n; 1065 h = yr / 10.0; 1066 w = xr / 10.0; 1067 xr += w; 1068 yr += h; 1069 xl = -w; 1070 yl = -h; 1071 PetscCall(PetscDrawSetCoordinates(draw, xl, yl, xr, yr)); 1072 PetscCall(PetscObjectCompose((PetscObject)A, "Zoomviewer", (PetscObject)viewer)); 1073 PetscCall(PetscDrawZoom(draw, MatView_SeqAIJ_Draw_Zoom, A)); 1074 PetscCall(PetscObjectCompose((PetscObject)A, "Zoomviewer", NULL)); 1075 PetscCall(PetscDrawSave(draw)); 1076 PetscFunctionReturn(PETSC_SUCCESS); 1077 } 1078 1079 PetscErrorCode MatView_SeqAIJ(Mat A, PetscViewer viewer) 1080 { 1081 PetscBool iascii, isbinary, isdraw; 1082 1083 PetscFunctionBegin; 1084 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1085 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 1086 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1087 if (iascii) PetscCall(MatView_SeqAIJ_ASCII(A, viewer)); 1088 else if (isbinary) PetscCall(MatView_SeqAIJ_Binary(A, viewer)); 1089 else if (isdraw) PetscCall(MatView_SeqAIJ_Draw(A, viewer)); 1090 PetscCall(MatView_SeqAIJ_Inode(A, viewer)); 1091 PetscFunctionReturn(PETSC_SUCCESS); 1092 } 1093 1094 PetscErrorCode MatAssemblyEnd_SeqAIJ(Mat A, MatAssemblyType mode) 1095 { 1096 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1097 PetscInt fshift = 0, i, *ai = a->i, *aj = a->j, *imax = a->imax; 1098 PetscInt m = A->rmap->n, *ip, N, *ailen = a->ilen, rmax = 0, n; 1099 MatScalar *aa = a->a, *ap; 1100 PetscReal ratio = 0.6; 1101 1102 PetscFunctionBegin; 1103 if (mode == MAT_FLUSH_ASSEMBLY) PetscFunctionReturn(PETSC_SUCCESS); 1104 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 1105 if (A->was_assembled && A->ass_nonzerostate == A->nonzerostate) { 1106 /* we need to respect users asking to use or not the inodes routine in between matrix assemblies, e.g., via MatSetOption(A, MAT_USE_INODES, val) */ 1107 PetscCall(MatAssemblyEnd_SeqAIJ_Inode(A, mode)); /* read the sparsity pattern */ 1108 PetscFunctionReturn(PETSC_SUCCESS); 1109 } 1110 1111 if (m) rmax = ailen[0]; /* determine row with most nonzeros */ 1112 for (i = 1; i < m; i++) { 1113 /* move each row back by the amount of empty slots (fshift) before it*/ 1114 fshift += imax[i - 1] - ailen[i - 1]; 1115 rmax = PetscMax(rmax, ailen[i]); 1116 if (fshift) { 1117 ip = aj + ai[i]; 1118 ap = aa + ai[i]; 1119 N = ailen[i]; 1120 PetscCall(PetscArraymove(ip - fshift, ip, N)); 1121 if (!A->structure_only) PetscCall(PetscArraymove(ap - fshift, ap, N)); 1122 } 1123 ai[i] = ai[i - 1] + ailen[i - 1]; 1124 } 1125 if (m) { 1126 fshift += imax[m - 1] - ailen[m - 1]; 1127 ai[m] = ai[m - 1] + ailen[m - 1]; 1128 } 1129 /* reset ilen and imax for each row */ 1130 a->nonzerorowcnt = 0; 1131 if (A->structure_only) { 1132 PetscCall(PetscFree(a->imax)); 1133 PetscCall(PetscFree(a->ilen)); 1134 } else { /* !A->structure_only */ 1135 for (i = 0; i < m; i++) { 1136 ailen[i] = imax[i] = ai[i + 1] - ai[i]; 1137 a->nonzerorowcnt += ((ai[i + 1] - ai[i]) > 0); 1138 } 1139 } 1140 a->nz = ai[m]; 1141 PetscCheck(!fshift || a->nounused != -1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unused space detected in matrix: %" PetscInt_FMT " X %" PetscInt_FMT ", %" PetscInt_FMT " unneeded", m, A->cmap->n, fshift); 1142 PetscCall(MatMarkDiagonal_SeqAIJ(A)); // since diagonal info is used a lot, it is helpful to set them up at the end of assembly 1143 a->diagonaldense = PETSC_TRUE; 1144 n = PetscMin(A->rmap->n, A->cmap->n); 1145 for (i = 0; i < n; i++) { 1146 if (a->diag[i] >= ai[i + 1]) { 1147 a->diagonaldense = PETSC_FALSE; 1148 break; 1149 } 1150 } 1151 PetscCall(PetscInfo(A, "Matrix size: %" PetscInt_FMT " X %" PetscInt_FMT "; storage space: %" PetscInt_FMT " unneeded,%" PetscInt_FMT " used\n", m, A->cmap->n, fshift, a->nz)); 1152 PetscCall(PetscInfo(A, "Number of mallocs during MatSetValues() is %" PetscInt_FMT "\n", a->reallocs)); 1153 PetscCall(PetscInfo(A, "Maximum nonzeros in any row is %" PetscInt_FMT "\n", rmax)); 1154 1155 A->info.mallocs += a->reallocs; 1156 a->reallocs = 0; 1157 A->info.nz_unneeded = (PetscReal)fshift; 1158 a->rmax = rmax; 1159 1160 if (!A->structure_only) PetscCall(MatCheckCompressedRow(A, a->nonzerorowcnt, &a->compressedrow, a->i, m, ratio)); 1161 PetscCall(MatAssemblyEnd_SeqAIJ_Inode(A, mode)); 1162 PetscFunctionReturn(PETSC_SUCCESS); 1163 } 1164 1165 static PetscErrorCode MatRealPart_SeqAIJ(Mat A) 1166 { 1167 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1168 PetscInt i, nz = a->nz; 1169 MatScalar *aa; 1170 1171 PetscFunctionBegin; 1172 PetscCall(MatSeqAIJGetArray(A, &aa)); 1173 for (i = 0; i < nz; i++) aa[i] = PetscRealPart(aa[i]); 1174 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 1175 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 1176 PetscFunctionReturn(PETSC_SUCCESS); 1177 } 1178 1179 static PetscErrorCode MatImaginaryPart_SeqAIJ(Mat A) 1180 { 1181 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1182 PetscInt i, nz = a->nz; 1183 MatScalar *aa; 1184 1185 PetscFunctionBegin; 1186 PetscCall(MatSeqAIJGetArray(A, &aa)); 1187 for (i = 0; i < nz; i++) aa[i] = PetscImaginaryPart(aa[i]); 1188 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 1189 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 1190 PetscFunctionReturn(PETSC_SUCCESS); 1191 } 1192 1193 PetscErrorCode MatZeroEntries_SeqAIJ(Mat A) 1194 { 1195 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1196 MatScalar *aa; 1197 1198 PetscFunctionBegin; 1199 PetscCall(MatSeqAIJGetArrayWrite(A, &aa)); 1200 PetscCall(PetscArrayzero(aa, a->i[A->rmap->n])); 1201 PetscCall(MatSeqAIJRestoreArrayWrite(A, &aa)); 1202 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 1203 PetscFunctionReturn(PETSC_SUCCESS); 1204 } 1205 1206 static PetscErrorCode MatReset_SeqAIJ(Mat A) 1207 { 1208 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1209 1210 PetscFunctionBegin; 1211 if (A->hash_active) { 1212 A->ops[0] = a->cops; 1213 PetscCall(PetscHMapIJVDestroy(&a->ht)); 1214 PetscCall(PetscFree(a->dnz)); 1215 A->hash_active = PETSC_FALSE; 1216 } 1217 1218 PetscCall(PetscLogObjectState((PetscObject)A, "Rows=%" PetscInt_FMT ", Cols=%" PetscInt_FMT ", NZ=%" PetscInt_FMT, A->rmap->n, A->cmap->n, a->nz)); 1219 PetscCall(MatSeqXAIJFreeAIJ(A, &a->a, &a->j, &a->i)); 1220 PetscCall(ISDestroy(&a->row)); 1221 PetscCall(ISDestroy(&a->col)); 1222 PetscCall(PetscFree(a->diag)); 1223 PetscCall(PetscFree(a->ibdiag)); 1224 PetscCall(PetscFree(a->imax)); 1225 PetscCall(PetscFree(a->ilen)); 1226 PetscCall(PetscFree(a->ipre)); 1227 PetscCall(PetscFree3(a->idiag, a->mdiag, a->ssor_work)); 1228 PetscCall(PetscFree(a->solve_work)); 1229 PetscCall(ISDestroy(&a->icol)); 1230 PetscCall(PetscFree(a->saved_values)); 1231 a->compressedrow.use = PETSC_FALSE; 1232 PetscCall(PetscFree2(a->compressedrow.i, a->compressedrow.rindex)); 1233 PetscCall(MatDestroy_SeqAIJ_Inode(A)); 1234 PetscFunctionReturn(PETSC_SUCCESS); 1235 } 1236 1237 static PetscErrorCode MatResetHash_SeqAIJ(Mat A) 1238 { 1239 PetscFunctionBegin; 1240 PetscCall(MatReset_SeqAIJ(A)); 1241 PetscCall(MatCreate_SeqAIJ_Inode(A)); 1242 PetscCall(MatSetUp_Seq_Hash(A)); 1243 A->nonzerostate++; 1244 PetscFunctionReturn(PETSC_SUCCESS); 1245 } 1246 1247 PetscErrorCode MatDestroy_SeqAIJ(Mat A) 1248 { 1249 PetscFunctionBegin; 1250 PetscCall(MatReset_SeqAIJ(A)); 1251 PetscCall(PetscFree(A->data)); 1252 1253 /* MatMatMultNumeric_SeqAIJ_SeqAIJ_Sorted may allocate this. 1254 That function is so heavily used (sometimes in an hidden way through multnumeric function pointers) 1255 that is hard to properly add this data to the MatProduct data. We free it here to avoid 1256 users reusing the matrix object with different data to incur in obscure segmentation faults 1257 due to different matrix sizes */ 1258 PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc__ab_dense", NULL)); 1259 1260 PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL)); 1261 PetscCall(PetscObjectComposeFunction((PetscObject)A, "PetscMatlabEnginePut_C", NULL)); 1262 PetscCall(PetscObjectComposeFunction((PetscObject)A, "PetscMatlabEngineGet_C", NULL)); 1263 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqAIJSetColumnIndices_C", NULL)); 1264 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatStoreValues_C", NULL)); 1265 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatRetrieveValues_C", NULL)); 1266 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqsbaij_C", NULL)); 1267 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqbaij_C", NULL)); 1268 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijperm_C", NULL)); 1269 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijsell_C", NULL)); 1270 #if defined(PETSC_HAVE_MKL_SPARSE) 1271 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijmkl_C", NULL)); 1272 #endif 1273 #if defined(PETSC_HAVE_CUDA) 1274 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijcusparse_C", NULL)); 1275 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaijcusparse_seqaij_C", NULL)); 1276 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaij_seqaijcusparse_C", NULL)); 1277 #endif 1278 #if defined(PETSC_HAVE_HIP) 1279 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijhipsparse_C", NULL)); 1280 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaijhipsparse_seqaij_C", NULL)); 1281 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaij_seqaijhipsparse_C", NULL)); 1282 #endif 1283 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 1284 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijkokkos_C", NULL)); 1285 #endif 1286 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijcrl_C", NULL)); 1287 #if defined(PETSC_HAVE_ELEMENTAL) 1288 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_elemental_C", NULL)); 1289 #endif 1290 #if defined(PETSC_HAVE_SCALAPACK) 1291 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_scalapack_C", NULL)); 1292 #endif 1293 #if defined(PETSC_HAVE_HYPRE) 1294 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_hypre_C", NULL)); 1295 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_transpose_seqaij_seqaij_C", NULL)); 1296 #endif 1297 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqdense_C", NULL)); 1298 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqsell_C", NULL)); 1299 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_is_C", NULL)); 1300 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatIsTranspose_C", NULL)); 1301 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatIsHermitianTranspose_C", NULL)); 1302 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqAIJSetPreallocation_C", NULL)); 1303 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatResetPreallocation_C", NULL)); 1304 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatResetHash_C", NULL)); 1305 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqAIJSetPreallocationCSR_C", NULL)); 1306 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatReorderForNonzeroDiagonal_C", NULL)); 1307 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_is_seqaij_C", NULL)); 1308 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqdense_seqaij_C", NULL)); 1309 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaij_seqaij_C", NULL)); 1310 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqAIJKron_C", NULL)); 1311 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", NULL)); 1312 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", NULL)); 1313 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatFactorGetSolverType_C", NULL)); 1314 /* these calls do not belong here: the subclasses Duplicate/Destroy are wrong */ 1315 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaijsell_seqaij_C", NULL)); 1316 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaijperm_seqaij_C", NULL)); 1317 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijviennacl_C", NULL)); 1318 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaijviennacl_seqdense_C", NULL)); 1319 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaijviennacl_seqaij_C", NULL)); 1320 PetscFunctionReturn(PETSC_SUCCESS); 1321 } 1322 1323 PetscErrorCode MatSetOption_SeqAIJ(Mat A, MatOption op, PetscBool flg) 1324 { 1325 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1326 1327 PetscFunctionBegin; 1328 switch (op) { 1329 case MAT_ROW_ORIENTED: 1330 a->roworiented = flg; 1331 break; 1332 case MAT_KEEP_NONZERO_PATTERN: 1333 a->keepnonzeropattern = flg; 1334 break; 1335 case MAT_NEW_NONZERO_LOCATIONS: 1336 a->nonew = (flg ? 0 : 1); 1337 break; 1338 case MAT_NEW_NONZERO_LOCATION_ERR: 1339 a->nonew = (flg ? -1 : 0); 1340 break; 1341 case MAT_NEW_NONZERO_ALLOCATION_ERR: 1342 a->nonew = (flg ? -2 : 0); 1343 break; 1344 case MAT_UNUSED_NONZERO_LOCATION_ERR: 1345 a->nounused = (flg ? -1 : 0); 1346 break; 1347 case MAT_IGNORE_ZERO_ENTRIES: 1348 a->ignorezeroentries = flg; 1349 break; 1350 case MAT_USE_INODES: 1351 PetscCall(MatSetOption_SeqAIJ_Inode(A, MAT_USE_INODES, flg)); 1352 break; 1353 case MAT_SUBMAT_SINGLEIS: 1354 A->submat_singleis = flg; 1355 break; 1356 case MAT_SORTED_FULL: 1357 if (flg) A->ops->setvalues = MatSetValues_SeqAIJ_SortedFull; 1358 else A->ops->setvalues = MatSetValues_SeqAIJ; 1359 break; 1360 case MAT_FORM_EXPLICIT_TRANSPOSE: 1361 A->form_explicit_transpose = flg; 1362 break; 1363 default: 1364 break; 1365 } 1366 PetscFunctionReturn(PETSC_SUCCESS); 1367 } 1368 1369 static PetscErrorCode MatGetDiagonal_SeqAIJ(Mat A, Vec v) 1370 { 1371 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1372 PetscInt i, j, n, *ai = a->i, *aj = a->j; 1373 PetscScalar *x; 1374 const PetscScalar *aa; 1375 1376 PetscFunctionBegin; 1377 PetscCall(VecGetLocalSize(v, &n)); 1378 PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 1379 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 1380 if (A->factortype == MAT_FACTOR_ILU || A->factortype == MAT_FACTOR_LU) { 1381 PetscInt *diag = a->diag; 1382 PetscCall(VecGetArrayWrite(v, &x)); 1383 for (i = 0; i < n; i++) x[i] = 1.0 / aa[diag[i]]; 1384 PetscCall(VecRestoreArrayWrite(v, &x)); 1385 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 1386 PetscFunctionReturn(PETSC_SUCCESS); 1387 } 1388 1389 PetscCall(VecGetArrayWrite(v, &x)); 1390 for (i = 0; i < n; i++) { 1391 x[i] = 0.0; 1392 for (j = ai[i]; j < ai[i + 1]; j++) { 1393 if (aj[j] == i) { 1394 x[i] = aa[j]; 1395 break; 1396 } 1397 } 1398 } 1399 PetscCall(VecRestoreArrayWrite(v, &x)); 1400 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 1401 PetscFunctionReturn(PETSC_SUCCESS); 1402 } 1403 1404 #include <../src/mat/impls/aij/seq/ftn-kernels/fmult.h> 1405 PetscErrorCode MatMultTransposeAdd_SeqAIJ(Mat A, Vec xx, Vec zz, Vec yy) 1406 { 1407 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1408 const MatScalar *aa; 1409 PetscScalar *y; 1410 const PetscScalar *x; 1411 PetscInt m = A->rmap->n; 1412 #if !defined(PETSC_USE_FORTRAN_KERNEL_MULTTRANSPOSEAIJ) 1413 const MatScalar *v; 1414 PetscScalar alpha; 1415 PetscInt n, i, j; 1416 const PetscInt *idx, *ii, *ridx = NULL; 1417 Mat_CompressedRow cprow = a->compressedrow; 1418 PetscBool usecprow = cprow.use; 1419 #endif 1420 1421 PetscFunctionBegin; 1422 if (zz != yy) PetscCall(VecCopy(zz, yy)); 1423 PetscCall(VecGetArrayRead(xx, &x)); 1424 PetscCall(VecGetArray(yy, &y)); 1425 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 1426 1427 #if defined(PETSC_USE_FORTRAN_KERNEL_MULTTRANSPOSEAIJ) 1428 fortranmulttransposeaddaij_(&m, x, a->i, a->j, aa, y); 1429 #else 1430 if (usecprow) { 1431 m = cprow.nrows; 1432 ii = cprow.i; 1433 ridx = cprow.rindex; 1434 } else { 1435 ii = a->i; 1436 } 1437 for (i = 0; i < m; i++) { 1438 idx = a->j + ii[i]; 1439 v = aa + ii[i]; 1440 n = ii[i + 1] - ii[i]; 1441 if (usecprow) { 1442 alpha = x[ridx[i]]; 1443 } else { 1444 alpha = x[i]; 1445 } 1446 for (j = 0; j < n; j++) y[idx[j]] += alpha * v[j]; 1447 } 1448 #endif 1449 PetscCall(PetscLogFlops(2.0 * a->nz)); 1450 PetscCall(VecRestoreArrayRead(xx, &x)); 1451 PetscCall(VecRestoreArray(yy, &y)); 1452 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 1453 PetscFunctionReturn(PETSC_SUCCESS); 1454 } 1455 1456 PetscErrorCode MatMultTranspose_SeqAIJ(Mat A, Vec xx, Vec yy) 1457 { 1458 PetscFunctionBegin; 1459 PetscCall(VecSet(yy, 0.0)); 1460 PetscCall(MatMultTransposeAdd_SeqAIJ(A, xx, yy, yy)); 1461 PetscFunctionReturn(PETSC_SUCCESS); 1462 } 1463 1464 #include <../src/mat/impls/aij/seq/ftn-kernels/fmult.h> 1465 1466 PetscErrorCode MatMult_SeqAIJ(Mat A, Vec xx, Vec yy) 1467 { 1468 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1469 PetscScalar *y; 1470 const PetscScalar *x; 1471 const MatScalar *a_a; 1472 PetscInt m = A->rmap->n; 1473 const PetscInt *ii, *ridx = NULL; 1474 PetscBool usecprow = a->compressedrow.use; 1475 1476 #if defined(PETSC_HAVE_PRAGMA_DISJOINT) 1477 #pragma disjoint(*x, *y, *aa) 1478 #endif 1479 1480 PetscFunctionBegin; 1481 if (a->inode.use && a->inode.checked) { 1482 PetscCall(MatMult_SeqAIJ_Inode(A, xx, yy)); 1483 PetscFunctionReturn(PETSC_SUCCESS); 1484 } 1485 PetscCall(MatSeqAIJGetArrayRead(A, &a_a)); 1486 PetscCall(VecGetArrayRead(xx, &x)); 1487 PetscCall(VecGetArray(yy, &y)); 1488 ii = a->i; 1489 if (usecprow) { /* use compressed row format */ 1490 PetscCall(PetscArrayzero(y, m)); 1491 m = a->compressedrow.nrows; 1492 ii = a->compressedrow.i; 1493 ridx = a->compressedrow.rindex; 1494 PetscPragmaUseOMPKernels(parallel for) 1495 for (PetscInt i = 0; i < m; i++) { 1496 PetscInt n = ii[i + 1] - ii[i]; 1497 const PetscInt *aj = a->j + ii[i]; 1498 const PetscScalar *aa = a_a + ii[i]; 1499 PetscScalar sum = 0.0; 1500 PetscSparseDensePlusDot(sum, x, aa, aj, n); 1501 /* for (j=0; j<n; j++) sum += (*aa++)*x[*aj++]; */ 1502 y[ridx[i]] = sum; 1503 } 1504 } else { /* do not use compressed row format */ 1505 #if defined(PETSC_USE_FORTRAN_KERNEL_MULTAIJ) 1506 fortranmultaij_(&m, x, ii, a->j, a_a, y); 1507 #else 1508 PetscPragmaUseOMPKernels(parallel for) 1509 for (PetscInt i = 0; i < m; i++) { 1510 PetscInt n = ii[i + 1] - ii[i]; 1511 const PetscInt *aj = a->j + ii[i]; 1512 const PetscScalar *aa = a_a + ii[i]; 1513 PetscScalar sum = 0.0; 1514 PetscSparseDensePlusDot(sum, x, aa, aj, n); 1515 y[i] = sum; 1516 } 1517 #endif 1518 } 1519 PetscCall(PetscLogFlops(2.0 * a->nz - a->nonzerorowcnt)); 1520 PetscCall(VecRestoreArrayRead(xx, &x)); 1521 PetscCall(VecRestoreArray(yy, &y)); 1522 PetscCall(MatSeqAIJRestoreArrayRead(A, &a_a)); 1523 PetscFunctionReturn(PETSC_SUCCESS); 1524 } 1525 1526 // HACK!!!!! Used by src/mat/tests/ex170.c 1527 PETSC_EXTERN PetscErrorCode MatMultMax_SeqAIJ(Mat A, Vec xx, Vec yy) 1528 { 1529 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1530 PetscScalar *y; 1531 const PetscScalar *x; 1532 const MatScalar *aa, *a_a; 1533 PetscInt m = A->rmap->n; 1534 const PetscInt *aj, *ii, *ridx = NULL; 1535 PetscInt n, i, nonzerorow = 0; 1536 PetscScalar sum; 1537 PetscBool usecprow = a->compressedrow.use; 1538 1539 #if defined(PETSC_HAVE_PRAGMA_DISJOINT) 1540 #pragma disjoint(*x, *y, *aa) 1541 #endif 1542 1543 PetscFunctionBegin; 1544 PetscCall(MatSeqAIJGetArrayRead(A, &a_a)); 1545 PetscCall(VecGetArrayRead(xx, &x)); 1546 PetscCall(VecGetArray(yy, &y)); 1547 if (usecprow) { /* use compressed row format */ 1548 m = a->compressedrow.nrows; 1549 ii = a->compressedrow.i; 1550 ridx = a->compressedrow.rindex; 1551 for (i = 0; i < m; i++) { 1552 n = ii[i + 1] - ii[i]; 1553 aj = a->j + ii[i]; 1554 aa = a_a + ii[i]; 1555 sum = 0.0; 1556 nonzerorow += (n > 0); 1557 PetscSparseDenseMaxDot(sum, x, aa, aj, n); 1558 /* for (j=0; j<n; j++) sum += (*aa++)*x[*aj++]; */ 1559 y[*ridx++] = sum; 1560 } 1561 } else { /* do not use compressed row format */ 1562 ii = a->i; 1563 for (i = 0; i < m; i++) { 1564 n = ii[i + 1] - ii[i]; 1565 aj = a->j + ii[i]; 1566 aa = a_a + ii[i]; 1567 sum = 0.0; 1568 nonzerorow += (n > 0); 1569 PetscSparseDenseMaxDot(sum, x, aa, aj, n); 1570 y[i] = sum; 1571 } 1572 } 1573 PetscCall(PetscLogFlops(2.0 * a->nz - nonzerorow)); 1574 PetscCall(VecRestoreArrayRead(xx, &x)); 1575 PetscCall(VecRestoreArray(yy, &y)); 1576 PetscCall(MatSeqAIJRestoreArrayRead(A, &a_a)); 1577 PetscFunctionReturn(PETSC_SUCCESS); 1578 } 1579 1580 // HACK!!!!! Used by src/mat/tests/ex170.c 1581 PETSC_EXTERN PetscErrorCode MatMultAddMax_SeqAIJ(Mat A, Vec xx, Vec yy, Vec zz) 1582 { 1583 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1584 PetscScalar *y, *z; 1585 const PetscScalar *x; 1586 const MatScalar *aa, *a_a; 1587 PetscInt m = A->rmap->n, *aj, *ii; 1588 PetscInt n, i, *ridx = NULL; 1589 PetscScalar sum; 1590 PetscBool usecprow = a->compressedrow.use; 1591 1592 PetscFunctionBegin; 1593 PetscCall(MatSeqAIJGetArrayRead(A, &a_a)); 1594 PetscCall(VecGetArrayRead(xx, &x)); 1595 PetscCall(VecGetArrayPair(yy, zz, &y, &z)); 1596 if (usecprow) { /* use compressed row format */ 1597 if (zz != yy) PetscCall(PetscArraycpy(z, y, m)); 1598 m = a->compressedrow.nrows; 1599 ii = a->compressedrow.i; 1600 ridx = a->compressedrow.rindex; 1601 for (i = 0; i < m; i++) { 1602 n = ii[i + 1] - ii[i]; 1603 aj = a->j + ii[i]; 1604 aa = a_a + ii[i]; 1605 sum = y[*ridx]; 1606 PetscSparseDenseMaxDot(sum, x, aa, aj, n); 1607 z[*ridx++] = sum; 1608 } 1609 } else { /* do not use compressed row format */ 1610 ii = a->i; 1611 for (i = 0; i < m; i++) { 1612 n = ii[i + 1] - ii[i]; 1613 aj = a->j + ii[i]; 1614 aa = a_a + ii[i]; 1615 sum = y[i]; 1616 PetscSparseDenseMaxDot(sum, x, aa, aj, n); 1617 z[i] = sum; 1618 } 1619 } 1620 PetscCall(PetscLogFlops(2.0 * a->nz)); 1621 PetscCall(VecRestoreArrayRead(xx, &x)); 1622 PetscCall(VecRestoreArrayPair(yy, zz, &y, &z)); 1623 PetscCall(MatSeqAIJRestoreArrayRead(A, &a_a)); 1624 PetscFunctionReturn(PETSC_SUCCESS); 1625 } 1626 1627 #include <../src/mat/impls/aij/seq/ftn-kernels/fmultadd.h> 1628 PetscErrorCode MatMultAdd_SeqAIJ(Mat A, Vec xx, Vec yy, Vec zz) 1629 { 1630 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1631 PetscScalar *y, *z; 1632 const PetscScalar *x; 1633 const MatScalar *a_a; 1634 const PetscInt *ii, *ridx = NULL; 1635 PetscInt m = A->rmap->n; 1636 PetscBool usecprow = a->compressedrow.use; 1637 1638 PetscFunctionBegin; 1639 if (a->inode.use && a->inode.checked) { 1640 PetscCall(MatMultAdd_SeqAIJ_Inode(A, xx, yy, zz)); 1641 PetscFunctionReturn(PETSC_SUCCESS); 1642 } 1643 PetscCall(MatSeqAIJGetArrayRead(A, &a_a)); 1644 PetscCall(VecGetArrayRead(xx, &x)); 1645 PetscCall(VecGetArrayPair(yy, zz, &y, &z)); 1646 if (usecprow) { /* use compressed row format */ 1647 if (zz != yy) PetscCall(PetscArraycpy(z, y, m)); 1648 m = a->compressedrow.nrows; 1649 ii = a->compressedrow.i; 1650 ridx = a->compressedrow.rindex; 1651 for (PetscInt i = 0; i < m; i++) { 1652 PetscInt n = ii[i + 1] - ii[i]; 1653 const PetscInt *aj = a->j + ii[i]; 1654 const PetscScalar *aa = a_a + ii[i]; 1655 PetscScalar sum = y[*ridx]; 1656 PetscSparseDensePlusDot(sum, x, aa, aj, n); 1657 z[*ridx++] = sum; 1658 } 1659 } else { /* do not use compressed row format */ 1660 ii = a->i; 1661 #if defined(PETSC_USE_FORTRAN_KERNEL_MULTADDAIJ) 1662 fortranmultaddaij_(&m, x, ii, a->j, a_a, y, z); 1663 #else 1664 PetscPragmaUseOMPKernels(parallel for) 1665 for (PetscInt i = 0; i < m; i++) { 1666 PetscInt n = ii[i + 1] - ii[i]; 1667 const PetscInt *aj = a->j + ii[i]; 1668 const PetscScalar *aa = a_a + ii[i]; 1669 PetscScalar sum = y[i]; 1670 PetscSparseDensePlusDot(sum, x, aa, aj, n); 1671 z[i] = sum; 1672 } 1673 #endif 1674 } 1675 PetscCall(PetscLogFlops(2.0 * a->nz)); 1676 PetscCall(VecRestoreArrayRead(xx, &x)); 1677 PetscCall(VecRestoreArrayPair(yy, zz, &y, &z)); 1678 PetscCall(MatSeqAIJRestoreArrayRead(A, &a_a)); 1679 PetscFunctionReturn(PETSC_SUCCESS); 1680 } 1681 1682 /* 1683 Adds diagonal pointers to sparse matrix nonzero structure. 1684 */ 1685 PetscErrorCode MatMarkDiagonal_SeqAIJ(Mat A) 1686 { 1687 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1688 PetscInt i, j, m = A->rmap->n; 1689 PetscBool alreadySet = PETSC_TRUE; 1690 1691 PetscFunctionBegin; 1692 if (!a->diag) { 1693 PetscCall(PetscMalloc1(m, &a->diag)); 1694 alreadySet = PETSC_FALSE; 1695 } 1696 for (i = 0; i < A->rmap->n; i++) { 1697 /* If A's diagonal is already correctly set, this fast track enables cheap and repeated MatMarkDiagonal_SeqAIJ() calls */ 1698 if (alreadySet) { 1699 PetscInt pos = a->diag[i]; 1700 if (pos >= a->i[i] && pos < a->i[i + 1] && a->j[pos] == i) continue; 1701 } 1702 1703 a->diag[i] = a->i[i + 1]; 1704 for (j = a->i[i]; j < a->i[i + 1]; j++) { 1705 if (a->j[j] == i) { 1706 a->diag[i] = j; 1707 break; 1708 } 1709 } 1710 } 1711 PetscFunctionReturn(PETSC_SUCCESS); 1712 } 1713 1714 static PetscErrorCode MatShift_SeqAIJ(Mat A, PetscScalar v) 1715 { 1716 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1717 const PetscInt *diag = (const PetscInt *)a->diag; 1718 const PetscInt *ii = (const PetscInt *)a->i; 1719 PetscInt i, *mdiag = NULL; 1720 PetscInt cnt = 0; /* how many diagonals are missing */ 1721 1722 PetscFunctionBegin; 1723 if (!A->preallocated || !a->nz) { 1724 PetscCall(MatSeqAIJSetPreallocation(A, 1, NULL)); 1725 PetscCall(MatShift_Basic(A, v)); 1726 PetscFunctionReturn(PETSC_SUCCESS); 1727 } 1728 1729 if (a->diagonaldense) { 1730 cnt = 0; 1731 } else { 1732 PetscCall(PetscCalloc1(A->rmap->n, &mdiag)); 1733 for (i = 0; i < A->rmap->n; i++) { 1734 if (i < A->cmap->n && diag[i] >= ii[i + 1]) { /* 'out of range' rows never have diagonals */ 1735 cnt++; 1736 mdiag[i] = 1; 1737 } 1738 } 1739 } 1740 if (!cnt) { 1741 PetscCall(MatShift_Basic(A, v)); 1742 } else { 1743 PetscScalar *olda = a->a; /* preserve pointers to current matrix nonzeros structure and values */ 1744 PetscInt *oldj = a->j, *oldi = a->i; 1745 PetscBool free_a = a->free_a, free_ij = a->free_ij; 1746 const PetscScalar *Aa; 1747 1748 PetscCall(MatSeqAIJGetArrayRead(A, &Aa)); // sync the host 1749 PetscCall(MatSeqAIJRestoreArrayRead(A, &Aa)); 1750 1751 a->a = NULL; 1752 a->j = NULL; 1753 a->i = NULL; 1754 /* increase the values in imax for each row where a diagonal is being inserted then reallocate the matrix data structures */ 1755 for (i = 0; i < PetscMin(A->rmap->n, A->cmap->n); i++) a->imax[i] += mdiag[i]; 1756 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(A, 0, a->imax)); 1757 1758 /* copy old values into new matrix data structure */ 1759 for (i = 0; i < A->rmap->n; i++) { 1760 PetscCall(MatSetValues(A, 1, &i, a->imax[i] - mdiag[i], &oldj[oldi[i]], &olda[oldi[i]], ADD_VALUES)); 1761 if (i < A->cmap->n) PetscCall(MatSetValue(A, i, i, v, ADD_VALUES)); 1762 } 1763 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 1764 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 1765 if (free_a) PetscCall(PetscShmgetDeallocateArray((void **)&olda)); 1766 if (free_ij) PetscCall(PetscShmgetDeallocateArray((void **)&oldj)); 1767 if (free_ij) PetscCall(PetscShmgetDeallocateArray((void **)&oldi)); 1768 } 1769 PetscCall(PetscFree(mdiag)); 1770 a->diagonaldense = PETSC_TRUE; 1771 PetscFunctionReturn(PETSC_SUCCESS); 1772 } 1773 1774 /* 1775 Checks for missing diagonals 1776 */ 1777 PetscErrorCode MatMissingDiagonal_SeqAIJ(Mat A, PetscBool *missing, PetscInt *d) 1778 { 1779 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1780 PetscInt *diag, *ii = a->i, i; 1781 1782 PetscFunctionBegin; 1783 *missing = PETSC_FALSE; 1784 if (A->rmap->n > 0 && !ii) { 1785 *missing = PETSC_TRUE; 1786 if (d) *d = 0; 1787 PetscCall(PetscInfo(A, "Matrix has no entries therefore is missing diagonal\n")); 1788 } else { 1789 PetscInt n; 1790 n = PetscMin(A->rmap->n, A->cmap->n); 1791 diag = a->diag; 1792 for (i = 0; i < n; i++) { 1793 if (diag[i] >= ii[i + 1]) { 1794 *missing = PETSC_TRUE; 1795 if (d) *d = i; 1796 PetscCall(PetscInfo(A, "Matrix is missing diagonal number %" PetscInt_FMT "\n", i)); 1797 break; 1798 } 1799 } 1800 } 1801 PetscFunctionReturn(PETSC_SUCCESS); 1802 } 1803 1804 #include <petscblaslapack.h> 1805 #include <petsc/private/kernels/blockinvert.h> 1806 1807 /* 1808 Note that values is allocated externally by the PC and then passed into this routine 1809 */ 1810 static PetscErrorCode MatInvertVariableBlockDiagonal_SeqAIJ(Mat A, PetscInt nblocks, const PetscInt *bsizes, PetscScalar *diag) 1811 { 1812 PetscInt n = A->rmap->n, i, ncnt = 0, *indx, j, bsizemax = 0, *v_pivots; 1813 PetscBool allowzeropivot, zeropivotdetected = PETSC_FALSE; 1814 const PetscReal shift = 0.0; 1815 PetscInt ipvt[5]; 1816 PetscCount flops = 0; 1817 PetscScalar work[25], *v_work; 1818 1819 PetscFunctionBegin; 1820 allowzeropivot = PetscNot(A->erroriffailure); 1821 for (i = 0; i < nblocks; i++) ncnt += bsizes[i]; 1822 PetscCheck(ncnt == n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total blocksizes %" PetscInt_FMT " doesn't match number matrix rows %" PetscInt_FMT, ncnt, n); 1823 for (i = 0; i < nblocks; i++) bsizemax = PetscMax(bsizemax, bsizes[i]); 1824 PetscCall(PetscMalloc1(bsizemax, &indx)); 1825 if (bsizemax > 7) PetscCall(PetscMalloc2(bsizemax, &v_work, bsizemax, &v_pivots)); 1826 ncnt = 0; 1827 for (i = 0; i < nblocks; i++) { 1828 for (j = 0; j < bsizes[i]; j++) indx[j] = ncnt + j; 1829 PetscCall(MatGetValues(A, bsizes[i], indx, bsizes[i], indx, diag)); 1830 switch (bsizes[i]) { 1831 case 1: 1832 *diag = 1.0 / (*diag); 1833 break; 1834 case 2: 1835 PetscCall(PetscKernel_A_gets_inverse_A_2(diag, shift, allowzeropivot, &zeropivotdetected)); 1836 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 1837 PetscCall(PetscKernel_A_gets_transpose_A_2(diag)); 1838 break; 1839 case 3: 1840 PetscCall(PetscKernel_A_gets_inverse_A_3(diag, shift, allowzeropivot, &zeropivotdetected)); 1841 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 1842 PetscCall(PetscKernel_A_gets_transpose_A_3(diag)); 1843 break; 1844 case 4: 1845 PetscCall(PetscKernel_A_gets_inverse_A_4(diag, shift, allowzeropivot, &zeropivotdetected)); 1846 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 1847 PetscCall(PetscKernel_A_gets_transpose_A_4(diag)); 1848 break; 1849 case 5: 1850 PetscCall(PetscKernel_A_gets_inverse_A_5(diag, ipvt, work, shift, allowzeropivot, &zeropivotdetected)); 1851 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 1852 PetscCall(PetscKernel_A_gets_transpose_A_5(diag)); 1853 break; 1854 case 6: 1855 PetscCall(PetscKernel_A_gets_inverse_A_6(diag, shift, allowzeropivot, &zeropivotdetected)); 1856 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 1857 PetscCall(PetscKernel_A_gets_transpose_A_6(diag)); 1858 break; 1859 case 7: 1860 PetscCall(PetscKernel_A_gets_inverse_A_7(diag, shift, allowzeropivot, &zeropivotdetected)); 1861 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 1862 PetscCall(PetscKernel_A_gets_transpose_A_7(diag)); 1863 break; 1864 default: 1865 PetscCall(PetscKernel_A_gets_inverse_A(bsizes[i], diag, v_pivots, v_work, allowzeropivot, &zeropivotdetected)); 1866 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 1867 PetscCall(PetscKernel_A_gets_transpose_A_N(diag, bsizes[i])); 1868 } 1869 ncnt += bsizes[i]; 1870 diag += bsizes[i] * bsizes[i]; 1871 flops += 2 * PetscPowInt64(bsizes[i], 3) / 3; 1872 } 1873 PetscCall(PetscLogFlops(flops)); 1874 if (bsizemax > 7) PetscCall(PetscFree2(v_work, v_pivots)); 1875 PetscCall(PetscFree(indx)); 1876 PetscFunctionReturn(PETSC_SUCCESS); 1877 } 1878 1879 /* 1880 Negative shift indicates do not generate an error if there is a zero diagonal, just invert it anyways 1881 */ 1882 static PetscErrorCode MatInvertDiagonal_SeqAIJ(Mat A, PetscScalar omega, PetscScalar fshift) 1883 { 1884 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1885 PetscInt i, *diag, m = A->rmap->n; 1886 const MatScalar *v; 1887 PetscScalar *idiag, *mdiag; 1888 1889 PetscFunctionBegin; 1890 if (a->idiagvalid) PetscFunctionReturn(PETSC_SUCCESS); 1891 PetscCall(MatMarkDiagonal_SeqAIJ(A)); 1892 diag = a->diag; 1893 if (!a->idiag) { PetscCall(PetscMalloc3(m, &a->idiag, m, &a->mdiag, m, &a->ssor_work)); } 1894 1895 mdiag = a->mdiag; 1896 idiag = a->idiag; 1897 PetscCall(MatSeqAIJGetArrayRead(A, &v)); 1898 if (omega == 1.0 && PetscRealPart(fshift) <= 0.0) { 1899 for (i = 0; i < m; i++) { 1900 mdiag[i] = v[diag[i]]; 1901 if (!PetscAbsScalar(mdiag[i])) { /* zero diagonal */ 1902 if (PetscRealPart(fshift)) { 1903 PetscCall(PetscInfo(A, "Zero diagonal on row %" PetscInt_FMT "\n", i)); 1904 A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 1905 A->factorerror_zeropivot_value = 0.0; 1906 A->factorerror_zeropivot_row = i; 1907 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Zero diagonal on row %" PetscInt_FMT, i); 1908 } 1909 idiag[i] = 1.0 / v[diag[i]]; 1910 } 1911 PetscCall(PetscLogFlops(m)); 1912 } else { 1913 for (i = 0; i < m; i++) { 1914 mdiag[i] = v[diag[i]]; 1915 idiag[i] = omega / (fshift + v[diag[i]]); 1916 } 1917 PetscCall(PetscLogFlops(2.0 * m)); 1918 } 1919 a->idiagvalid = PETSC_TRUE; 1920 PetscCall(MatSeqAIJRestoreArrayRead(A, &v)); 1921 PetscFunctionReturn(PETSC_SUCCESS); 1922 } 1923 1924 PetscErrorCode MatSOR_SeqAIJ(Mat A, Vec bb, PetscReal omega, MatSORType flag, PetscReal fshift, PetscInt its, PetscInt lits, Vec xx) 1925 { 1926 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1927 PetscScalar *x, d, sum, *t, scale; 1928 const MatScalar *v, *idiag = NULL, *mdiag, *aa; 1929 const PetscScalar *b, *bs, *xb, *ts; 1930 PetscInt n, m = A->rmap->n, i; 1931 const PetscInt *idx, *diag; 1932 1933 PetscFunctionBegin; 1934 if (a->inode.use && a->inode.checked && omega == 1.0 && fshift == 0.0) { 1935 PetscCall(MatSOR_SeqAIJ_Inode(A, bb, omega, flag, fshift, its, lits, xx)); 1936 PetscFunctionReturn(PETSC_SUCCESS); 1937 } 1938 its = its * lits; 1939 1940 if (fshift != a->fshift || omega != a->omega) a->idiagvalid = PETSC_FALSE; /* must recompute idiag[] */ 1941 if (!a->idiagvalid) PetscCall(MatInvertDiagonal_SeqAIJ(A, omega, fshift)); 1942 a->fshift = fshift; 1943 a->omega = omega; 1944 1945 diag = a->diag; 1946 t = a->ssor_work; 1947 idiag = a->idiag; 1948 mdiag = a->mdiag; 1949 1950 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 1951 PetscCall(VecGetArray(xx, &x)); 1952 PetscCall(VecGetArrayRead(bb, &b)); 1953 /* We count flops by assuming the upper triangular and lower triangular parts have the same number of nonzeros */ 1954 if (flag == SOR_APPLY_UPPER) { 1955 /* apply (U + D/omega) to the vector */ 1956 bs = b; 1957 for (i = 0; i < m; i++) { 1958 d = fshift + mdiag[i]; 1959 n = a->i[i + 1] - diag[i] - 1; 1960 idx = a->j + diag[i] + 1; 1961 v = aa + diag[i] + 1; 1962 sum = b[i] * d / omega; 1963 PetscSparseDensePlusDot(sum, bs, v, idx, n); 1964 x[i] = sum; 1965 } 1966 PetscCall(VecRestoreArray(xx, &x)); 1967 PetscCall(VecRestoreArrayRead(bb, &b)); 1968 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 1969 PetscCall(PetscLogFlops(a->nz)); 1970 PetscFunctionReturn(PETSC_SUCCESS); 1971 } 1972 1973 PetscCheck(flag != SOR_APPLY_LOWER, PETSC_COMM_SELF, PETSC_ERR_SUP, "SOR_APPLY_LOWER is not implemented"); 1974 if (flag & SOR_EISENSTAT) { 1975 /* Let A = L + U + D; where L is lower triangular, 1976 U is upper triangular, E = D/omega; This routine applies 1977 1978 (L + E)^{-1} A (U + E)^{-1} 1979 1980 to a vector efficiently using Eisenstat's trick. 1981 */ 1982 scale = (2.0 / omega) - 1.0; 1983 1984 /* x = (E + U)^{-1} b */ 1985 for (i = m - 1; i >= 0; i--) { 1986 n = a->i[i + 1] - diag[i] - 1; 1987 idx = a->j + diag[i] + 1; 1988 v = aa + diag[i] + 1; 1989 sum = b[i]; 1990 PetscSparseDenseMinusDot(sum, x, v, idx, n); 1991 x[i] = sum * idiag[i]; 1992 } 1993 1994 /* t = b - (2*E - D)x */ 1995 v = aa; 1996 for (i = 0; i < m; i++) t[i] = b[i] - scale * (v[*diag++]) * x[i]; 1997 1998 /* t = (E + L)^{-1}t */ 1999 ts = t; 2000 diag = a->diag; 2001 for (i = 0; i < m; i++) { 2002 n = diag[i] - a->i[i]; 2003 idx = a->j + a->i[i]; 2004 v = aa + a->i[i]; 2005 sum = t[i]; 2006 PetscSparseDenseMinusDot(sum, ts, v, idx, n); 2007 t[i] = sum * idiag[i]; 2008 /* x = x + t */ 2009 x[i] += t[i]; 2010 } 2011 2012 PetscCall(PetscLogFlops(6.0 * m - 1 + 2.0 * a->nz)); 2013 PetscCall(VecRestoreArray(xx, &x)); 2014 PetscCall(VecRestoreArrayRead(bb, &b)); 2015 PetscFunctionReturn(PETSC_SUCCESS); 2016 } 2017 if (flag & SOR_ZERO_INITIAL_GUESS) { 2018 if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) { 2019 for (i = 0; i < m; i++) { 2020 n = diag[i] - a->i[i]; 2021 idx = a->j + a->i[i]; 2022 v = aa + a->i[i]; 2023 sum = b[i]; 2024 PetscSparseDenseMinusDot(sum, x, v, idx, n); 2025 t[i] = sum; 2026 x[i] = sum * idiag[i]; 2027 } 2028 xb = t; 2029 PetscCall(PetscLogFlops(a->nz)); 2030 } else xb = b; 2031 if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP) { 2032 for (i = m - 1; i >= 0; i--) { 2033 n = a->i[i + 1] - diag[i] - 1; 2034 idx = a->j + diag[i] + 1; 2035 v = aa + diag[i] + 1; 2036 sum = xb[i]; 2037 PetscSparseDenseMinusDot(sum, x, v, idx, n); 2038 if (xb == b) { 2039 x[i] = sum * idiag[i]; 2040 } else { 2041 x[i] = (1 - omega) * x[i] + sum * idiag[i]; /* omega in idiag */ 2042 } 2043 } 2044 PetscCall(PetscLogFlops(a->nz)); /* assumes 1/2 in upper */ 2045 } 2046 its--; 2047 } 2048 while (its--) { 2049 if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) { 2050 for (i = 0; i < m; i++) { 2051 /* lower */ 2052 n = diag[i] - a->i[i]; 2053 idx = a->j + a->i[i]; 2054 v = aa + a->i[i]; 2055 sum = b[i]; 2056 PetscSparseDenseMinusDot(sum, x, v, idx, n); 2057 t[i] = sum; /* save application of the lower-triangular part */ 2058 /* upper */ 2059 n = a->i[i + 1] - diag[i] - 1; 2060 idx = a->j + diag[i] + 1; 2061 v = aa + diag[i] + 1; 2062 PetscSparseDenseMinusDot(sum, x, v, idx, n); 2063 x[i] = (1. - omega) * x[i] + sum * idiag[i]; /* omega in idiag */ 2064 } 2065 xb = t; 2066 PetscCall(PetscLogFlops(2.0 * a->nz)); 2067 } else xb = b; 2068 if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP) { 2069 for (i = m - 1; i >= 0; i--) { 2070 sum = xb[i]; 2071 if (xb == b) { 2072 /* whole matrix (no checkpointing available) */ 2073 n = a->i[i + 1] - a->i[i]; 2074 idx = a->j + a->i[i]; 2075 v = aa + a->i[i]; 2076 PetscSparseDenseMinusDot(sum, x, v, idx, n); 2077 x[i] = (1. - omega) * x[i] + (sum + mdiag[i] * x[i]) * idiag[i]; 2078 } else { /* lower-triangular part has been saved, so only apply upper-triangular */ 2079 n = a->i[i + 1] - diag[i] - 1; 2080 idx = a->j + diag[i] + 1; 2081 v = aa + diag[i] + 1; 2082 PetscSparseDenseMinusDot(sum, x, v, idx, n); 2083 x[i] = (1. - omega) * x[i] + sum * idiag[i]; /* omega in idiag */ 2084 } 2085 } 2086 if (xb == b) { 2087 PetscCall(PetscLogFlops(2.0 * a->nz)); 2088 } else { 2089 PetscCall(PetscLogFlops(a->nz)); /* assumes 1/2 in upper */ 2090 } 2091 } 2092 } 2093 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 2094 PetscCall(VecRestoreArray(xx, &x)); 2095 PetscCall(VecRestoreArrayRead(bb, &b)); 2096 PetscFunctionReturn(PETSC_SUCCESS); 2097 } 2098 2099 static PetscErrorCode MatGetInfo_SeqAIJ(Mat A, MatInfoType flag, MatInfo *info) 2100 { 2101 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2102 2103 PetscFunctionBegin; 2104 info->block_size = 1.0; 2105 info->nz_allocated = a->maxnz; 2106 info->nz_used = a->nz; 2107 info->nz_unneeded = (a->maxnz - a->nz); 2108 info->assemblies = A->num_ass; 2109 info->mallocs = A->info.mallocs; 2110 info->memory = 0; /* REVIEW ME */ 2111 if (A->factortype) { 2112 info->fill_ratio_given = A->info.fill_ratio_given; 2113 info->fill_ratio_needed = A->info.fill_ratio_needed; 2114 info->factor_mallocs = A->info.factor_mallocs; 2115 } else { 2116 info->fill_ratio_given = 0; 2117 info->fill_ratio_needed = 0; 2118 info->factor_mallocs = 0; 2119 } 2120 PetscFunctionReturn(PETSC_SUCCESS); 2121 } 2122 2123 static PetscErrorCode MatZeroRows_SeqAIJ(Mat A, PetscInt N, const PetscInt rows[], PetscScalar diag, Vec x, Vec b) 2124 { 2125 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2126 PetscInt i, m = A->rmap->n - 1; 2127 const PetscScalar *xx; 2128 PetscScalar *bb, *aa; 2129 PetscInt d = 0; 2130 2131 PetscFunctionBegin; 2132 if (x && b) { 2133 PetscCall(VecGetArrayRead(x, &xx)); 2134 PetscCall(VecGetArray(b, &bb)); 2135 for (i = 0; i < N; i++) { 2136 PetscCheck(rows[i] >= 0 && rows[i] <= m, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "row %" PetscInt_FMT " out of range", rows[i]); 2137 if (rows[i] >= A->cmap->n) continue; 2138 bb[rows[i]] = diag * xx[rows[i]]; 2139 } 2140 PetscCall(VecRestoreArrayRead(x, &xx)); 2141 PetscCall(VecRestoreArray(b, &bb)); 2142 } 2143 2144 PetscCall(MatSeqAIJGetArray(A, &aa)); 2145 if (a->keepnonzeropattern) { 2146 for (i = 0; i < N; i++) { 2147 PetscCheck(rows[i] >= 0 && rows[i] <= m, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "row %" PetscInt_FMT " out of range", rows[i]); 2148 PetscCall(PetscArrayzero(&aa[a->i[rows[i]]], a->ilen[rows[i]])); 2149 } 2150 if (diag != 0.0) { 2151 for (i = 0; i < N; i++) { 2152 d = rows[i]; 2153 if (rows[i] >= A->cmap->n) continue; 2154 PetscCheck(a->diag[d] < a->i[d + 1], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Matrix is missing diagonal entry in the zeroed row %" PetscInt_FMT, d); 2155 } 2156 for (i = 0; i < N; i++) { 2157 if (rows[i] >= A->cmap->n) continue; 2158 aa[a->diag[rows[i]]] = diag; 2159 } 2160 } 2161 } else { 2162 if (diag != 0.0) { 2163 for (i = 0; i < N; i++) { 2164 PetscCheck(rows[i] >= 0 && rows[i] <= m, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "row %" PetscInt_FMT " out of range", rows[i]); 2165 if (a->ilen[rows[i]] > 0) { 2166 if (rows[i] >= A->cmap->n) { 2167 a->ilen[rows[i]] = 0; 2168 } else { 2169 a->ilen[rows[i]] = 1; 2170 aa[a->i[rows[i]]] = diag; 2171 a->j[a->i[rows[i]]] = rows[i]; 2172 } 2173 } else if (rows[i] < A->cmap->n) { /* in case row was completely empty */ 2174 PetscCall(MatSetValues_SeqAIJ(A, 1, &rows[i], 1, &rows[i], &diag, INSERT_VALUES)); 2175 } 2176 } 2177 } else { 2178 for (i = 0; i < N; i++) { 2179 PetscCheck(rows[i] >= 0 && rows[i] <= m, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "row %" PetscInt_FMT " out of range", rows[i]); 2180 a->ilen[rows[i]] = 0; 2181 } 2182 } 2183 A->nonzerostate++; 2184 } 2185 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 2186 PetscUseTypeMethod(A, assemblyend, MAT_FINAL_ASSEMBLY); 2187 PetscFunctionReturn(PETSC_SUCCESS); 2188 } 2189 2190 static PetscErrorCode MatZeroRowsColumns_SeqAIJ(Mat A, PetscInt N, const PetscInt rows[], PetscScalar diag, Vec x, Vec b) 2191 { 2192 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2193 PetscInt i, j, m = A->rmap->n - 1, d = 0; 2194 PetscBool missing, *zeroed, vecs = PETSC_FALSE; 2195 const PetscScalar *xx; 2196 PetscScalar *bb, *aa; 2197 2198 PetscFunctionBegin; 2199 if (!N) PetscFunctionReturn(PETSC_SUCCESS); 2200 PetscCall(MatSeqAIJGetArray(A, &aa)); 2201 if (x && b) { 2202 PetscCall(VecGetArrayRead(x, &xx)); 2203 PetscCall(VecGetArray(b, &bb)); 2204 vecs = PETSC_TRUE; 2205 } 2206 PetscCall(PetscCalloc1(A->rmap->n, &zeroed)); 2207 for (i = 0; i < N; i++) { 2208 PetscCheck(rows[i] >= 0 && rows[i] <= m, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "row %" PetscInt_FMT " out of range", rows[i]); 2209 PetscCall(PetscArrayzero(PetscSafePointerPlusOffset(aa, a->i[rows[i]]), a->ilen[rows[i]])); 2210 2211 zeroed[rows[i]] = PETSC_TRUE; 2212 } 2213 for (i = 0; i < A->rmap->n; i++) { 2214 if (!zeroed[i]) { 2215 for (j = a->i[i]; j < a->i[i + 1]; j++) { 2216 if (a->j[j] < A->rmap->n && zeroed[a->j[j]]) { 2217 if (vecs) bb[i] -= aa[j] * xx[a->j[j]]; 2218 aa[j] = 0.0; 2219 } 2220 } 2221 } else if (vecs && i < A->cmap->N) bb[i] = diag * xx[i]; 2222 } 2223 if (x && b) { 2224 PetscCall(VecRestoreArrayRead(x, &xx)); 2225 PetscCall(VecRestoreArray(b, &bb)); 2226 } 2227 PetscCall(PetscFree(zeroed)); 2228 if (diag != 0.0) { 2229 PetscCall(MatMissingDiagonal_SeqAIJ(A, &missing, &d)); 2230 if (missing) { 2231 for (i = 0; i < N; i++) { 2232 if (rows[i] >= A->cmap->N) continue; 2233 PetscCheck(!a->nonew || rows[i] < d, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Matrix is missing diagonal entry in row %" PetscInt_FMT " (%" PetscInt_FMT ")", d, rows[i]); 2234 PetscCall(MatSetValues_SeqAIJ(A, 1, &rows[i], 1, &rows[i], &diag, INSERT_VALUES)); 2235 } 2236 } else { 2237 for (i = 0; i < N; i++) aa[a->diag[rows[i]]] = diag; 2238 } 2239 } 2240 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 2241 PetscUseTypeMethod(A, assemblyend, MAT_FINAL_ASSEMBLY); 2242 PetscFunctionReturn(PETSC_SUCCESS); 2243 } 2244 2245 PetscErrorCode MatGetRow_SeqAIJ(Mat A, PetscInt row, PetscInt *nz, PetscInt **idx, PetscScalar **v) 2246 { 2247 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2248 const PetscScalar *aa; 2249 2250 PetscFunctionBegin; 2251 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 2252 *nz = a->i[row + 1] - a->i[row]; 2253 if (v) *v = PetscSafePointerPlusOffset((PetscScalar *)aa, a->i[row]); 2254 if (idx) { 2255 if (*nz && a->j) *idx = a->j + a->i[row]; 2256 else *idx = NULL; 2257 } 2258 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 2259 PetscFunctionReturn(PETSC_SUCCESS); 2260 } 2261 2262 PetscErrorCode MatRestoreRow_SeqAIJ(Mat A, PetscInt row, PetscInt *nz, PetscInt **idx, PetscScalar **v) 2263 { 2264 PetscFunctionBegin; 2265 PetscFunctionReturn(PETSC_SUCCESS); 2266 } 2267 2268 static PetscErrorCode MatNorm_SeqAIJ(Mat A, NormType type, PetscReal *nrm) 2269 { 2270 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2271 const MatScalar *v; 2272 PetscReal sum = 0.0; 2273 PetscInt i, j; 2274 2275 PetscFunctionBegin; 2276 PetscCall(MatSeqAIJGetArrayRead(A, &v)); 2277 if (type == NORM_FROBENIUS) { 2278 #if defined(PETSC_USE_REAL___FP16) 2279 PetscBLASInt one = 1, nz = a->nz; 2280 PetscCallBLAS("BLASnrm2", *nrm = BLASnrm2_(&nz, v, &one)); 2281 #else 2282 for (i = 0; i < a->nz; i++) { 2283 sum += PetscRealPart(PetscConj(*v) * (*v)); 2284 v++; 2285 } 2286 *nrm = PetscSqrtReal(sum); 2287 #endif 2288 PetscCall(PetscLogFlops(2.0 * a->nz)); 2289 } else if (type == NORM_1) { 2290 PetscReal *tmp; 2291 PetscInt *jj = a->j; 2292 PetscCall(PetscCalloc1(A->cmap->n + 1, &tmp)); 2293 *nrm = 0.0; 2294 for (j = 0; j < a->nz; j++) { 2295 tmp[*jj++] += PetscAbsScalar(*v); 2296 v++; 2297 } 2298 for (j = 0; j < A->cmap->n; j++) { 2299 if (tmp[j] > *nrm) *nrm = tmp[j]; 2300 } 2301 PetscCall(PetscFree(tmp)); 2302 PetscCall(PetscLogFlops(PetscMax(a->nz - 1, 0))); 2303 } else if (type == NORM_INFINITY) { 2304 *nrm = 0.0; 2305 for (j = 0; j < A->rmap->n; j++) { 2306 const PetscScalar *v2 = PetscSafePointerPlusOffset(v, a->i[j]); 2307 sum = 0.0; 2308 for (i = 0; i < a->i[j + 1] - a->i[j]; i++) { 2309 sum += PetscAbsScalar(*v2); 2310 v2++; 2311 } 2312 if (sum > *nrm) *nrm = sum; 2313 } 2314 PetscCall(PetscLogFlops(PetscMax(a->nz - 1, 0))); 2315 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for two norm"); 2316 PetscCall(MatSeqAIJRestoreArrayRead(A, &v)); 2317 PetscFunctionReturn(PETSC_SUCCESS); 2318 } 2319 2320 static PetscErrorCode MatIsTranspose_SeqAIJ(Mat A, Mat B, PetscReal tol, PetscBool *f) 2321 { 2322 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data, *bij = (Mat_SeqAIJ *)B->data; 2323 PetscInt *adx, *bdx, *aii, *bii, *aptr, *bptr; 2324 const MatScalar *va, *vb; 2325 PetscInt ma, na, mb, nb, i; 2326 2327 PetscFunctionBegin; 2328 PetscCall(MatGetSize(A, &ma, &na)); 2329 PetscCall(MatGetSize(B, &mb, &nb)); 2330 if (ma != nb || na != mb) { 2331 *f = PETSC_FALSE; 2332 PetscFunctionReturn(PETSC_SUCCESS); 2333 } 2334 PetscCall(MatSeqAIJGetArrayRead(A, &va)); 2335 PetscCall(MatSeqAIJGetArrayRead(B, &vb)); 2336 aii = aij->i; 2337 bii = bij->i; 2338 adx = aij->j; 2339 bdx = bij->j; 2340 PetscCall(PetscMalloc1(ma, &aptr)); 2341 PetscCall(PetscMalloc1(mb, &bptr)); 2342 for (i = 0; i < ma; i++) aptr[i] = aii[i]; 2343 for (i = 0; i < mb; i++) bptr[i] = bii[i]; 2344 2345 *f = PETSC_TRUE; 2346 for (i = 0; i < ma; i++) { 2347 while (aptr[i] < aii[i + 1]) { 2348 PetscInt idc, idr; 2349 PetscScalar vc, vr; 2350 /* column/row index/value */ 2351 idc = adx[aptr[i]]; 2352 idr = bdx[bptr[idc]]; 2353 vc = va[aptr[i]]; 2354 vr = vb[bptr[idc]]; 2355 if (i != idr || PetscAbsScalar(vc - vr) > tol) { 2356 *f = PETSC_FALSE; 2357 goto done; 2358 } else { 2359 aptr[i]++; 2360 if (B || i != idc) bptr[idc]++; 2361 } 2362 } 2363 } 2364 done: 2365 PetscCall(PetscFree(aptr)); 2366 PetscCall(PetscFree(bptr)); 2367 PetscCall(MatSeqAIJRestoreArrayRead(A, &va)); 2368 PetscCall(MatSeqAIJRestoreArrayRead(B, &vb)); 2369 PetscFunctionReturn(PETSC_SUCCESS); 2370 } 2371 2372 static PetscErrorCode MatIsHermitianTranspose_SeqAIJ(Mat A, Mat B, PetscReal tol, PetscBool *f) 2373 { 2374 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data, *bij = (Mat_SeqAIJ *)B->data; 2375 PetscInt *adx, *bdx, *aii, *bii, *aptr, *bptr; 2376 MatScalar *va, *vb; 2377 PetscInt ma, na, mb, nb, i; 2378 2379 PetscFunctionBegin; 2380 PetscCall(MatGetSize(A, &ma, &na)); 2381 PetscCall(MatGetSize(B, &mb, &nb)); 2382 if (ma != nb || na != mb) { 2383 *f = PETSC_FALSE; 2384 PetscFunctionReturn(PETSC_SUCCESS); 2385 } 2386 aii = aij->i; 2387 bii = bij->i; 2388 adx = aij->j; 2389 bdx = bij->j; 2390 va = aij->a; 2391 vb = bij->a; 2392 PetscCall(PetscMalloc1(ma, &aptr)); 2393 PetscCall(PetscMalloc1(mb, &bptr)); 2394 for (i = 0; i < ma; i++) aptr[i] = aii[i]; 2395 for (i = 0; i < mb; i++) bptr[i] = bii[i]; 2396 2397 *f = PETSC_TRUE; 2398 for (i = 0; i < ma; i++) { 2399 while (aptr[i] < aii[i + 1]) { 2400 PetscInt idc, idr; 2401 PetscScalar vc, vr; 2402 /* column/row index/value */ 2403 idc = adx[aptr[i]]; 2404 idr = bdx[bptr[idc]]; 2405 vc = va[aptr[i]]; 2406 vr = vb[bptr[idc]]; 2407 if (i != idr || PetscAbsScalar(vc - PetscConj(vr)) > tol) { 2408 *f = PETSC_FALSE; 2409 goto done; 2410 } else { 2411 aptr[i]++; 2412 if (B || i != idc) bptr[idc]++; 2413 } 2414 } 2415 } 2416 done: 2417 PetscCall(PetscFree(aptr)); 2418 PetscCall(PetscFree(bptr)); 2419 PetscFunctionReturn(PETSC_SUCCESS); 2420 } 2421 2422 PetscErrorCode MatDiagonalScale_SeqAIJ(Mat A, Vec ll, Vec rr) 2423 { 2424 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2425 const PetscScalar *l, *r; 2426 PetscScalar x; 2427 MatScalar *v; 2428 PetscInt i, j, m = A->rmap->n, n = A->cmap->n, M, nz = a->nz; 2429 const PetscInt *jj; 2430 2431 PetscFunctionBegin; 2432 if (ll) { 2433 /* The local size is used so that VecMPI can be passed to this routine 2434 by MatDiagonalScale_MPIAIJ */ 2435 PetscCall(VecGetLocalSize(ll, &m)); 2436 PetscCheck(m == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Left scaling vector wrong length"); 2437 PetscCall(VecGetArrayRead(ll, &l)); 2438 PetscCall(MatSeqAIJGetArray(A, &v)); 2439 for (i = 0; i < m; i++) { 2440 x = l[i]; 2441 M = a->i[i + 1] - a->i[i]; 2442 for (j = 0; j < M; j++) (*v++) *= x; 2443 } 2444 PetscCall(VecRestoreArrayRead(ll, &l)); 2445 PetscCall(PetscLogFlops(nz)); 2446 PetscCall(MatSeqAIJRestoreArray(A, &v)); 2447 } 2448 if (rr) { 2449 PetscCall(VecGetLocalSize(rr, &n)); 2450 PetscCheck(n == A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Right scaling vector wrong length"); 2451 PetscCall(VecGetArrayRead(rr, &r)); 2452 PetscCall(MatSeqAIJGetArray(A, &v)); 2453 jj = a->j; 2454 for (i = 0; i < nz; i++) (*v++) *= r[*jj++]; 2455 PetscCall(MatSeqAIJRestoreArray(A, &v)); 2456 PetscCall(VecRestoreArrayRead(rr, &r)); 2457 PetscCall(PetscLogFlops(nz)); 2458 } 2459 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 2460 PetscFunctionReturn(PETSC_SUCCESS); 2461 } 2462 2463 PetscErrorCode MatCreateSubMatrix_SeqAIJ(Mat A, IS isrow, IS iscol, PetscInt csize, MatReuse scall, Mat *B) 2464 { 2465 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *c; 2466 PetscInt *smap, i, k, kstart, kend, oldcols = A->cmap->n, *lens; 2467 PetscInt row, mat_i, *mat_j, tcol, first, step, *mat_ilen, sum, lensi; 2468 const PetscInt *irow, *icol; 2469 const PetscScalar *aa; 2470 PetscInt nrows, ncols; 2471 PetscInt *starts, *j_new, *i_new, *aj = a->j, *ai = a->i, ii, *ailen = a->ilen; 2472 MatScalar *a_new, *mat_a, *c_a; 2473 Mat C; 2474 PetscBool stride; 2475 2476 PetscFunctionBegin; 2477 PetscCall(ISGetIndices(isrow, &irow)); 2478 PetscCall(ISGetLocalSize(isrow, &nrows)); 2479 PetscCall(ISGetLocalSize(iscol, &ncols)); 2480 2481 PetscCall(PetscObjectTypeCompare((PetscObject)iscol, ISSTRIDE, &stride)); 2482 if (stride) { 2483 PetscCall(ISStrideGetInfo(iscol, &first, &step)); 2484 } else { 2485 first = 0; 2486 step = 0; 2487 } 2488 if (stride && step == 1) { 2489 /* special case of contiguous rows */ 2490 PetscCall(PetscMalloc2(nrows, &lens, nrows, &starts)); 2491 /* loop over new rows determining lens and starting points */ 2492 for (i = 0; i < nrows; i++) { 2493 kstart = ai[irow[i]]; 2494 kend = kstart + ailen[irow[i]]; 2495 starts[i] = kstart; 2496 for (k = kstart; k < kend; k++) { 2497 if (aj[k] >= first) { 2498 starts[i] = k; 2499 break; 2500 } 2501 } 2502 sum = 0; 2503 while (k < kend) { 2504 if (aj[k++] >= first + ncols) break; 2505 sum++; 2506 } 2507 lens[i] = sum; 2508 } 2509 /* create submatrix */ 2510 if (scall == MAT_REUSE_MATRIX) { 2511 PetscInt n_cols, n_rows; 2512 PetscCall(MatGetSize(*B, &n_rows, &n_cols)); 2513 PetscCheck(n_rows == nrows && n_cols == ncols, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Reused submatrix wrong size"); 2514 PetscCall(MatZeroEntries(*B)); 2515 C = *B; 2516 } else { 2517 PetscInt rbs, cbs; 2518 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C)); 2519 PetscCall(MatSetSizes(C, nrows, ncols, PETSC_DETERMINE, PETSC_DETERMINE)); 2520 PetscCall(ISGetBlockSize(isrow, &rbs)); 2521 PetscCall(ISGetBlockSize(iscol, &cbs)); 2522 PetscCall(MatSetBlockSizes(C, rbs, cbs)); 2523 PetscCall(MatSetType(C, ((PetscObject)A)->type_name)); 2524 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(C, 0, lens)); 2525 } 2526 c = (Mat_SeqAIJ *)C->data; 2527 2528 /* loop over rows inserting into submatrix */ 2529 PetscCall(MatSeqAIJGetArrayWrite(C, &a_new)); // Not 'a_new = c->a-new', since that raw usage ignores offload state of C 2530 j_new = c->j; 2531 i_new = c->i; 2532 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 2533 for (i = 0; i < nrows; i++) { 2534 ii = starts[i]; 2535 lensi = lens[i]; 2536 if (lensi) { 2537 for (k = 0; k < lensi; k++) *j_new++ = aj[ii + k] - first; 2538 PetscCall(PetscArraycpy(a_new, aa + starts[i], lensi)); 2539 a_new += lensi; 2540 } 2541 i_new[i + 1] = i_new[i] + lensi; 2542 c->ilen[i] = lensi; 2543 } 2544 PetscCall(MatSeqAIJRestoreArrayWrite(C, &a_new)); // Set C's offload state properly 2545 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 2546 PetscCall(PetscFree2(lens, starts)); 2547 } else { 2548 PetscCall(ISGetIndices(iscol, &icol)); 2549 PetscCall(PetscCalloc1(oldcols, &smap)); 2550 PetscCall(PetscMalloc1(1 + nrows, &lens)); 2551 for (i = 0; i < ncols; i++) { 2552 PetscCheck(icol[i] < oldcols, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Requesting column beyond largest column icol[%" PetscInt_FMT "] %" PetscInt_FMT " >= A->cmap->n %" PetscInt_FMT, i, icol[i], oldcols); 2553 smap[icol[i]] = i + 1; 2554 } 2555 2556 /* determine lens of each row */ 2557 for (i = 0; i < nrows; i++) { 2558 kstart = ai[irow[i]]; 2559 kend = kstart + a->ilen[irow[i]]; 2560 lens[i] = 0; 2561 for (k = kstart; k < kend; k++) { 2562 if (smap[aj[k]]) lens[i]++; 2563 } 2564 } 2565 /* Create and fill new matrix */ 2566 if (scall == MAT_REUSE_MATRIX) { 2567 PetscBool equal; 2568 2569 c = (Mat_SeqAIJ *)((*B)->data); 2570 PetscCheck((*B)->rmap->n == nrows && (*B)->cmap->n == ncols, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Cannot reuse matrix. wrong size"); 2571 PetscCall(PetscArraycmp(c->ilen, lens, (*B)->rmap->n, &equal)); 2572 PetscCheck(equal, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Cannot reuse matrix. wrong number of nonzeros"); 2573 PetscCall(PetscArrayzero(c->ilen, (*B)->rmap->n)); 2574 C = *B; 2575 } else { 2576 PetscInt rbs, cbs; 2577 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C)); 2578 PetscCall(MatSetSizes(C, nrows, ncols, PETSC_DETERMINE, PETSC_DETERMINE)); 2579 PetscCall(ISGetBlockSize(isrow, &rbs)); 2580 PetscCall(ISGetBlockSize(iscol, &cbs)); 2581 if (rbs > 1 || cbs > 1) PetscCall(MatSetBlockSizes(C, rbs, cbs)); 2582 PetscCall(MatSetType(C, ((PetscObject)A)->type_name)); 2583 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(C, 0, lens)); 2584 } 2585 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 2586 2587 c = (Mat_SeqAIJ *)C->data; 2588 PetscCall(MatSeqAIJGetArrayWrite(C, &c_a)); // Not 'c->a', since that raw usage ignores offload state of C 2589 for (i = 0; i < nrows; i++) { 2590 row = irow[i]; 2591 kstart = ai[row]; 2592 kend = kstart + a->ilen[row]; 2593 mat_i = c->i[i]; 2594 mat_j = PetscSafePointerPlusOffset(c->j, mat_i); 2595 mat_a = PetscSafePointerPlusOffset(c_a, mat_i); 2596 mat_ilen = c->ilen + i; 2597 for (k = kstart; k < kend; k++) { 2598 if ((tcol = smap[a->j[k]])) { 2599 *mat_j++ = tcol - 1; 2600 *mat_a++ = aa[k]; 2601 (*mat_ilen)++; 2602 } 2603 } 2604 } 2605 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 2606 /* Free work space */ 2607 PetscCall(ISRestoreIndices(iscol, &icol)); 2608 PetscCall(PetscFree(smap)); 2609 PetscCall(PetscFree(lens)); 2610 /* sort */ 2611 for (i = 0; i < nrows; i++) { 2612 PetscInt ilen; 2613 2614 mat_i = c->i[i]; 2615 mat_j = PetscSafePointerPlusOffset(c->j, mat_i); 2616 mat_a = PetscSafePointerPlusOffset(c_a, mat_i); 2617 ilen = c->ilen[i]; 2618 PetscCall(PetscSortIntWithScalarArray(ilen, mat_j, mat_a)); 2619 } 2620 PetscCall(MatSeqAIJRestoreArrayWrite(C, &c_a)); 2621 } 2622 #if defined(PETSC_HAVE_DEVICE) 2623 PetscCall(MatBindToCPU(C, A->boundtocpu)); 2624 #endif 2625 PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY)); 2626 PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY)); 2627 2628 PetscCall(ISRestoreIndices(isrow, &irow)); 2629 *B = C; 2630 PetscFunctionReturn(PETSC_SUCCESS); 2631 } 2632 2633 static PetscErrorCode MatGetMultiProcBlock_SeqAIJ(Mat mat, MPI_Comm subComm, MatReuse scall, Mat *subMat) 2634 { 2635 Mat B; 2636 2637 PetscFunctionBegin; 2638 if (scall == MAT_INITIAL_MATRIX) { 2639 PetscCall(MatCreate(subComm, &B)); 2640 PetscCall(MatSetSizes(B, mat->rmap->n, mat->cmap->n, mat->rmap->n, mat->cmap->n)); 2641 PetscCall(MatSetBlockSizesFromMats(B, mat, mat)); 2642 PetscCall(MatSetType(B, MATSEQAIJ)); 2643 PetscCall(MatDuplicateNoCreate_SeqAIJ(B, mat, MAT_COPY_VALUES, PETSC_TRUE)); 2644 *subMat = B; 2645 } else { 2646 PetscCall(MatCopy_SeqAIJ(mat, *subMat, SAME_NONZERO_PATTERN)); 2647 } 2648 PetscFunctionReturn(PETSC_SUCCESS); 2649 } 2650 2651 static PetscErrorCode MatILUFactor_SeqAIJ(Mat inA, IS row, IS col, const MatFactorInfo *info) 2652 { 2653 Mat_SeqAIJ *a = (Mat_SeqAIJ *)inA->data; 2654 Mat outA; 2655 PetscBool row_identity, col_identity; 2656 2657 PetscFunctionBegin; 2658 PetscCheck(info->levels == 0, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only levels=0 supported for in-place ilu"); 2659 2660 PetscCall(ISIdentity(row, &row_identity)); 2661 PetscCall(ISIdentity(col, &col_identity)); 2662 2663 outA = inA; 2664 outA->factortype = MAT_FACTOR_LU; 2665 PetscCall(PetscFree(inA->solvertype)); 2666 PetscCall(PetscStrallocpy(MATSOLVERPETSC, &inA->solvertype)); 2667 2668 PetscCall(PetscObjectReference((PetscObject)row)); 2669 PetscCall(ISDestroy(&a->row)); 2670 2671 a->row = row; 2672 2673 PetscCall(PetscObjectReference((PetscObject)col)); 2674 PetscCall(ISDestroy(&a->col)); 2675 2676 a->col = col; 2677 2678 /* Create the inverse permutation so that it can be used in MatLUFactorNumeric() */ 2679 PetscCall(ISDestroy(&a->icol)); 2680 PetscCall(ISInvertPermutation(col, PETSC_DECIDE, &a->icol)); 2681 2682 if (!a->solve_work) { /* this matrix may have been factored before */ 2683 PetscCall(PetscMalloc1(inA->rmap->n + 1, &a->solve_work)); 2684 } 2685 2686 PetscCall(MatMarkDiagonal_SeqAIJ(inA)); 2687 if (row_identity && col_identity) { 2688 PetscCall(MatLUFactorNumeric_SeqAIJ_inplace(outA, inA, info)); 2689 } else { 2690 PetscCall(MatLUFactorNumeric_SeqAIJ_InplaceWithPerm(outA, inA, info)); 2691 } 2692 PetscFunctionReturn(PETSC_SUCCESS); 2693 } 2694 2695 PetscErrorCode MatScale_SeqAIJ(Mat inA, PetscScalar alpha) 2696 { 2697 Mat_SeqAIJ *a = (Mat_SeqAIJ *)inA->data; 2698 PetscScalar *v; 2699 PetscBLASInt one = 1, bnz; 2700 2701 PetscFunctionBegin; 2702 PetscCall(MatSeqAIJGetArray(inA, &v)); 2703 PetscCall(PetscBLASIntCast(a->nz, &bnz)); 2704 PetscCallBLAS("BLASscal", BLASscal_(&bnz, &alpha, v, &one)); 2705 PetscCall(PetscLogFlops(a->nz)); 2706 PetscCall(MatSeqAIJRestoreArray(inA, &v)); 2707 PetscCall(MatSeqAIJInvalidateDiagonal(inA)); 2708 PetscFunctionReturn(PETSC_SUCCESS); 2709 } 2710 2711 PetscErrorCode MatDestroySubMatrix_Private(Mat_SubSppt *submatj) 2712 { 2713 PetscInt i; 2714 2715 PetscFunctionBegin; 2716 if (!submatj->id) { /* delete data that are linked only to submats[id=0] */ 2717 PetscCall(PetscFree4(submatj->sbuf1, submatj->ptr, submatj->tmp, submatj->ctr)); 2718 2719 for (i = 0; i < submatj->nrqr; ++i) PetscCall(PetscFree(submatj->sbuf2[i])); 2720 PetscCall(PetscFree3(submatj->sbuf2, submatj->req_size, submatj->req_source1)); 2721 2722 if (submatj->rbuf1) { 2723 PetscCall(PetscFree(submatj->rbuf1[0])); 2724 PetscCall(PetscFree(submatj->rbuf1)); 2725 } 2726 2727 for (i = 0; i < submatj->nrqs; ++i) PetscCall(PetscFree(submatj->rbuf3[i])); 2728 PetscCall(PetscFree3(submatj->req_source2, submatj->rbuf2, submatj->rbuf3)); 2729 PetscCall(PetscFree(submatj->pa)); 2730 } 2731 2732 #if defined(PETSC_USE_CTABLE) 2733 PetscCall(PetscHMapIDestroy(&submatj->rmap)); 2734 if (submatj->cmap_loc) PetscCall(PetscFree(submatj->cmap_loc)); 2735 PetscCall(PetscFree(submatj->rmap_loc)); 2736 #else 2737 PetscCall(PetscFree(submatj->rmap)); 2738 #endif 2739 2740 if (!submatj->allcolumns) { 2741 #if defined(PETSC_USE_CTABLE) 2742 PetscCall(PetscHMapIDestroy(&submatj->cmap)); 2743 #else 2744 PetscCall(PetscFree(submatj->cmap)); 2745 #endif 2746 } 2747 PetscCall(PetscFree(submatj->row2proc)); 2748 2749 PetscCall(PetscFree(submatj)); 2750 PetscFunctionReturn(PETSC_SUCCESS); 2751 } 2752 2753 PetscErrorCode MatDestroySubMatrix_SeqAIJ(Mat C) 2754 { 2755 Mat_SeqAIJ *c = (Mat_SeqAIJ *)C->data; 2756 Mat_SubSppt *submatj = c->submatis1; 2757 2758 PetscFunctionBegin; 2759 PetscCall((*submatj->destroy)(C)); 2760 PetscCall(MatDestroySubMatrix_Private(submatj)); 2761 PetscFunctionReturn(PETSC_SUCCESS); 2762 } 2763 2764 /* Note this has code duplication with MatDestroySubMatrices_SeqBAIJ() */ 2765 static PetscErrorCode MatDestroySubMatrices_SeqAIJ(PetscInt n, Mat *mat[]) 2766 { 2767 PetscInt i; 2768 Mat C; 2769 Mat_SeqAIJ *c; 2770 Mat_SubSppt *submatj; 2771 2772 PetscFunctionBegin; 2773 for (i = 0; i < n; i++) { 2774 C = (*mat)[i]; 2775 c = (Mat_SeqAIJ *)C->data; 2776 submatj = c->submatis1; 2777 if (submatj) { 2778 if (--((PetscObject)C)->refct <= 0) { 2779 PetscCall(PetscFree(C->factorprefix)); 2780 PetscCall((*submatj->destroy)(C)); 2781 PetscCall(MatDestroySubMatrix_Private(submatj)); 2782 PetscCall(PetscFree(C->defaultvectype)); 2783 PetscCall(PetscFree(C->defaultrandtype)); 2784 PetscCall(PetscLayoutDestroy(&C->rmap)); 2785 PetscCall(PetscLayoutDestroy(&C->cmap)); 2786 PetscCall(PetscHeaderDestroy(&C)); 2787 } 2788 } else { 2789 PetscCall(MatDestroy(&C)); 2790 } 2791 } 2792 2793 /* Destroy Dummy submatrices created for reuse */ 2794 PetscCall(MatDestroySubMatrices_Dummy(n, mat)); 2795 2796 PetscCall(PetscFree(*mat)); 2797 PetscFunctionReturn(PETSC_SUCCESS); 2798 } 2799 2800 static PetscErrorCode MatCreateSubMatrices_SeqAIJ(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *B[]) 2801 { 2802 PetscInt i; 2803 2804 PetscFunctionBegin; 2805 if (scall == MAT_INITIAL_MATRIX) PetscCall(PetscCalloc1(n + 1, B)); 2806 2807 for (i = 0; i < n; i++) PetscCall(MatCreateSubMatrix_SeqAIJ(A, irow[i], icol[i], PETSC_DECIDE, scall, &(*B)[i])); 2808 PetscFunctionReturn(PETSC_SUCCESS); 2809 } 2810 2811 static PetscErrorCode MatIncreaseOverlap_SeqAIJ(Mat A, PetscInt is_max, IS is[], PetscInt ov) 2812 { 2813 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2814 PetscInt row, i, j, k, l, ll, m, n, *nidx, isz, val; 2815 const PetscInt *idx; 2816 PetscInt start, end, *ai, *aj, bs = A->rmap->bs == A->cmap->bs ? A->rmap->bs : 1; 2817 PetscBT table; 2818 2819 PetscFunctionBegin; 2820 m = A->rmap->n / bs; 2821 ai = a->i; 2822 aj = a->j; 2823 2824 PetscCheck(ov >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "illegal negative overlap value used"); 2825 2826 PetscCall(PetscMalloc1(m + 1, &nidx)); 2827 PetscCall(PetscBTCreate(m, &table)); 2828 2829 for (i = 0; i < is_max; i++) { 2830 /* Initialize the two local arrays */ 2831 isz = 0; 2832 PetscCall(PetscBTMemzero(m, table)); 2833 2834 /* Extract the indices, assume there can be duplicate entries */ 2835 PetscCall(ISGetIndices(is[i], &idx)); 2836 PetscCall(ISGetLocalSize(is[i], &n)); 2837 2838 if (bs > 1) { 2839 /* Enter these into the temp arrays. I.e., mark table[row], enter row into new index */ 2840 for (j = 0; j < n; ++j) { 2841 if (!PetscBTLookupSet(table, idx[j] / bs)) nidx[isz++] = idx[j] / bs; 2842 } 2843 PetscCall(ISRestoreIndices(is[i], &idx)); 2844 PetscCall(ISDestroy(&is[i])); 2845 2846 k = 0; 2847 for (j = 0; j < ov; j++) { /* for each overlap */ 2848 n = isz; 2849 for (; k < n; k++) { /* do only those rows in nidx[k], which are not done yet */ 2850 for (ll = 0; ll < bs; ll++) { 2851 row = bs * nidx[k] + ll; 2852 start = ai[row]; 2853 end = ai[row + 1]; 2854 for (l = start; l < end; l++) { 2855 val = aj[l] / bs; 2856 if (!PetscBTLookupSet(table, val)) nidx[isz++] = val; 2857 } 2858 } 2859 } 2860 } 2861 PetscCall(ISCreateBlock(PETSC_COMM_SELF, bs, isz, nidx, PETSC_COPY_VALUES, is + i)); 2862 } else { 2863 /* Enter these into the temp arrays. I.e., mark table[row], enter row into new index */ 2864 for (j = 0; j < n; ++j) { 2865 if (!PetscBTLookupSet(table, idx[j])) nidx[isz++] = idx[j]; 2866 } 2867 PetscCall(ISRestoreIndices(is[i], &idx)); 2868 PetscCall(ISDestroy(&is[i])); 2869 2870 k = 0; 2871 for (j = 0; j < ov; j++) { /* for each overlap */ 2872 n = isz; 2873 for (; k < n; k++) { /* do only those rows in nidx[k], which are not done yet */ 2874 row = nidx[k]; 2875 start = ai[row]; 2876 end = ai[row + 1]; 2877 for (l = start; l < end; l++) { 2878 val = aj[l]; 2879 if (!PetscBTLookupSet(table, val)) nidx[isz++] = val; 2880 } 2881 } 2882 } 2883 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, isz, nidx, PETSC_COPY_VALUES, is + i)); 2884 } 2885 } 2886 PetscCall(PetscBTDestroy(&table)); 2887 PetscCall(PetscFree(nidx)); 2888 PetscFunctionReturn(PETSC_SUCCESS); 2889 } 2890 2891 static PetscErrorCode MatPermute_SeqAIJ(Mat A, IS rowp, IS colp, Mat *B) 2892 { 2893 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2894 PetscInt i, nz = 0, m = A->rmap->n, n = A->cmap->n; 2895 const PetscInt *row, *col; 2896 PetscInt *cnew, j, *lens; 2897 IS icolp, irowp; 2898 PetscInt *cwork = NULL; 2899 PetscScalar *vwork = NULL; 2900 2901 PetscFunctionBegin; 2902 PetscCall(ISInvertPermutation(rowp, PETSC_DECIDE, &irowp)); 2903 PetscCall(ISGetIndices(irowp, &row)); 2904 PetscCall(ISInvertPermutation(colp, PETSC_DECIDE, &icolp)); 2905 PetscCall(ISGetIndices(icolp, &col)); 2906 2907 /* determine lengths of permuted rows */ 2908 PetscCall(PetscMalloc1(m + 1, &lens)); 2909 for (i = 0; i < m; i++) lens[row[i]] = a->i[i + 1] - a->i[i]; 2910 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B)); 2911 PetscCall(MatSetSizes(*B, m, n, m, n)); 2912 PetscCall(MatSetBlockSizesFromMats(*B, A, A)); 2913 PetscCall(MatSetType(*B, ((PetscObject)A)->type_name)); 2914 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*B, 0, lens)); 2915 PetscCall(PetscFree(lens)); 2916 2917 PetscCall(PetscMalloc1(n, &cnew)); 2918 for (i = 0; i < m; i++) { 2919 PetscCall(MatGetRow_SeqAIJ(A, i, &nz, &cwork, &vwork)); 2920 for (j = 0; j < nz; j++) cnew[j] = col[cwork[j]]; 2921 PetscCall(MatSetValues_SeqAIJ(*B, 1, &row[i], nz, cnew, vwork, INSERT_VALUES)); 2922 PetscCall(MatRestoreRow_SeqAIJ(A, i, &nz, &cwork, &vwork)); 2923 } 2924 PetscCall(PetscFree(cnew)); 2925 2926 (*B)->assembled = PETSC_FALSE; 2927 2928 #if defined(PETSC_HAVE_DEVICE) 2929 PetscCall(MatBindToCPU(*B, A->boundtocpu)); 2930 #endif 2931 PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 2932 PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 2933 PetscCall(ISRestoreIndices(irowp, &row)); 2934 PetscCall(ISRestoreIndices(icolp, &col)); 2935 PetscCall(ISDestroy(&irowp)); 2936 PetscCall(ISDestroy(&icolp)); 2937 if (rowp == colp) PetscCall(MatPropagateSymmetryOptions(A, *B)); 2938 PetscFunctionReturn(PETSC_SUCCESS); 2939 } 2940 2941 PetscErrorCode MatCopy_SeqAIJ(Mat A, Mat B, MatStructure str) 2942 { 2943 PetscFunctionBegin; 2944 /* If the two matrices have the same copy implementation, use fast copy. */ 2945 if (str == SAME_NONZERO_PATTERN && (A->ops->copy == B->ops->copy)) { 2946 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2947 Mat_SeqAIJ *b = (Mat_SeqAIJ *)B->data; 2948 const PetscScalar *aa; 2949 PetscScalar *bb; 2950 2951 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 2952 PetscCall(MatSeqAIJGetArrayWrite(B, &bb)); 2953 2954 PetscCheck(a->i[A->rmap->n] == b->i[B->rmap->n], PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of nonzeros in two matrices are different %" PetscInt_FMT " != %" PetscInt_FMT, a->i[A->rmap->n], b->i[B->rmap->n]); 2955 PetscCall(PetscArraycpy(bb, aa, a->i[A->rmap->n])); 2956 PetscCall(PetscObjectStateIncrease((PetscObject)B)); 2957 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 2958 PetscCall(MatSeqAIJRestoreArrayWrite(B, &bb)); 2959 } else { 2960 PetscCall(MatCopy_Basic(A, B, str)); 2961 } 2962 PetscFunctionReturn(PETSC_SUCCESS); 2963 } 2964 2965 PETSC_INTERN PetscErrorCode MatSeqAIJGetArray_SeqAIJ(Mat A, PetscScalar *array[]) 2966 { 2967 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2968 2969 PetscFunctionBegin; 2970 *array = a->a; 2971 PetscFunctionReturn(PETSC_SUCCESS); 2972 } 2973 2974 PETSC_INTERN PetscErrorCode MatSeqAIJRestoreArray_SeqAIJ(Mat A, PetscScalar *array[]) 2975 { 2976 PetscFunctionBegin; 2977 *array = NULL; 2978 PetscFunctionReturn(PETSC_SUCCESS); 2979 } 2980 2981 /* 2982 Computes the number of nonzeros per row needed for preallocation when X and Y 2983 have different nonzero structure. 2984 */ 2985 PetscErrorCode MatAXPYGetPreallocation_SeqX_private(PetscInt m, const PetscInt *xi, const PetscInt *xj, const PetscInt *yi, const PetscInt *yj, PetscInt *nnz) 2986 { 2987 PetscInt i, j, k, nzx, nzy; 2988 2989 PetscFunctionBegin; 2990 /* Set the number of nonzeros in the new matrix */ 2991 for (i = 0; i < m; i++) { 2992 const PetscInt *xjj = PetscSafePointerPlusOffset(xj, xi[i]), *yjj = PetscSafePointerPlusOffset(yj, yi[i]); 2993 nzx = xi[i + 1] - xi[i]; 2994 nzy = yi[i + 1] - yi[i]; 2995 nnz[i] = 0; 2996 for (j = 0, k = 0; j < nzx; j++) { /* Point in X */ 2997 for (; k < nzy && yjj[k] < xjj[j]; k++) nnz[i]++; /* Catch up to X */ 2998 if (k < nzy && yjj[k] == xjj[j]) k++; /* Skip duplicate */ 2999 nnz[i]++; 3000 } 3001 for (; k < nzy; k++) nnz[i]++; 3002 } 3003 PetscFunctionReturn(PETSC_SUCCESS); 3004 } 3005 3006 PetscErrorCode MatAXPYGetPreallocation_SeqAIJ(Mat Y, Mat X, PetscInt *nnz) 3007 { 3008 PetscInt m = Y->rmap->N; 3009 Mat_SeqAIJ *x = (Mat_SeqAIJ *)X->data; 3010 Mat_SeqAIJ *y = (Mat_SeqAIJ *)Y->data; 3011 3012 PetscFunctionBegin; 3013 /* Set the number of nonzeros in the new matrix */ 3014 PetscCall(MatAXPYGetPreallocation_SeqX_private(m, x->i, x->j, y->i, y->j, nnz)); 3015 PetscFunctionReturn(PETSC_SUCCESS); 3016 } 3017 3018 PetscErrorCode MatAXPY_SeqAIJ(Mat Y, PetscScalar a, Mat X, MatStructure str) 3019 { 3020 Mat_SeqAIJ *x = (Mat_SeqAIJ *)X->data, *y = (Mat_SeqAIJ *)Y->data; 3021 3022 PetscFunctionBegin; 3023 if (str == UNKNOWN_NONZERO_PATTERN || (PetscDefined(USE_DEBUG) && str == SAME_NONZERO_PATTERN)) { 3024 PetscBool e = x->nz == y->nz ? PETSC_TRUE : PETSC_FALSE; 3025 if (e) { 3026 PetscCall(PetscArraycmp(x->i, y->i, Y->rmap->n + 1, &e)); 3027 if (e) { 3028 PetscCall(PetscArraycmp(x->j, y->j, y->nz, &e)); 3029 if (e) str = SAME_NONZERO_PATTERN; 3030 } 3031 } 3032 if (!e) PetscCheck(str != SAME_NONZERO_PATTERN, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MatStructure is not SAME_NONZERO_PATTERN"); 3033 } 3034 if (str == SAME_NONZERO_PATTERN) { 3035 const PetscScalar *xa; 3036 PetscScalar *ya, alpha = a; 3037 PetscBLASInt one = 1, bnz; 3038 3039 PetscCall(PetscBLASIntCast(x->nz, &bnz)); 3040 PetscCall(MatSeqAIJGetArray(Y, &ya)); 3041 PetscCall(MatSeqAIJGetArrayRead(X, &xa)); 3042 PetscCallBLAS("BLASaxpy", BLASaxpy_(&bnz, &alpha, xa, &one, ya, &one)); 3043 PetscCall(MatSeqAIJRestoreArrayRead(X, &xa)); 3044 PetscCall(MatSeqAIJRestoreArray(Y, &ya)); 3045 PetscCall(PetscLogFlops(2.0 * bnz)); 3046 PetscCall(MatSeqAIJInvalidateDiagonal(Y)); 3047 PetscCall(PetscObjectStateIncrease((PetscObject)Y)); 3048 } else if (str == SUBSET_NONZERO_PATTERN) { /* nonzeros of X is a subset of Y's */ 3049 PetscCall(MatAXPY_Basic(Y, a, X, str)); 3050 } else { 3051 Mat B; 3052 PetscInt *nnz; 3053 PetscCall(PetscMalloc1(Y->rmap->N, &nnz)); 3054 PetscCall(MatCreate(PetscObjectComm((PetscObject)Y), &B)); 3055 PetscCall(PetscObjectSetName((PetscObject)B, ((PetscObject)Y)->name)); 3056 PetscCall(MatSetLayouts(B, Y->rmap, Y->cmap)); 3057 PetscCall(MatSetType(B, ((PetscObject)Y)->type_name)); 3058 PetscCall(MatAXPYGetPreallocation_SeqAIJ(Y, X, nnz)); 3059 PetscCall(MatSeqAIJSetPreallocation(B, 0, nnz)); 3060 PetscCall(MatAXPY_BasicWithPreallocation(B, Y, a, X, str)); 3061 PetscCall(MatHeaderMerge(Y, &B)); 3062 PetscCall(MatSeqAIJCheckInode(Y)); 3063 PetscCall(PetscFree(nnz)); 3064 } 3065 PetscFunctionReturn(PETSC_SUCCESS); 3066 } 3067 3068 PETSC_INTERN PetscErrorCode MatConjugate_SeqAIJ(Mat mat) 3069 { 3070 #if defined(PETSC_USE_COMPLEX) 3071 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3072 PetscInt i, nz; 3073 PetscScalar *a; 3074 3075 PetscFunctionBegin; 3076 nz = aij->nz; 3077 PetscCall(MatSeqAIJGetArray(mat, &a)); 3078 for (i = 0; i < nz; i++) a[i] = PetscConj(a[i]); 3079 PetscCall(MatSeqAIJRestoreArray(mat, &a)); 3080 #else 3081 PetscFunctionBegin; 3082 #endif 3083 PetscFunctionReturn(PETSC_SUCCESS); 3084 } 3085 3086 static PetscErrorCode MatGetRowMaxAbs_SeqAIJ(Mat A, Vec v, PetscInt idx[]) 3087 { 3088 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3089 PetscInt i, j, m = A->rmap->n, *ai, *aj, ncols, n; 3090 PetscReal atmp; 3091 PetscScalar *x; 3092 const MatScalar *aa, *av; 3093 3094 PetscFunctionBegin; 3095 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3096 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3097 aa = av; 3098 ai = a->i; 3099 aj = a->j; 3100 3101 PetscCall(VecGetArrayWrite(v, &x)); 3102 PetscCall(VecGetLocalSize(v, &n)); 3103 PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 3104 for (i = 0; i < m; i++) { 3105 ncols = ai[1] - ai[0]; 3106 ai++; 3107 x[i] = 0; 3108 for (j = 0; j < ncols; j++) { 3109 atmp = PetscAbsScalar(*aa); 3110 if (PetscAbsScalar(x[i]) < atmp) { 3111 x[i] = atmp; 3112 if (idx) idx[i] = *aj; 3113 } 3114 aa++; 3115 aj++; 3116 } 3117 } 3118 PetscCall(VecRestoreArrayWrite(v, &x)); 3119 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3120 PetscFunctionReturn(PETSC_SUCCESS); 3121 } 3122 3123 static PetscErrorCode MatGetRowSumAbs_SeqAIJ(Mat A, Vec v) 3124 { 3125 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3126 PetscInt i, j, m = A->rmap->n, *ai, ncols, n; 3127 PetscScalar *x; 3128 const MatScalar *aa, *av; 3129 3130 PetscFunctionBegin; 3131 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3132 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3133 aa = av; 3134 ai = a->i; 3135 3136 PetscCall(VecGetArrayWrite(v, &x)); 3137 PetscCall(VecGetLocalSize(v, &n)); 3138 PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 3139 for (i = 0; i < m; i++) { 3140 ncols = ai[1] - ai[0]; 3141 ai++; 3142 x[i] = 0; 3143 for (j = 0; j < ncols; j++) { 3144 x[i] += PetscAbsScalar(*aa); 3145 aa++; 3146 } 3147 } 3148 PetscCall(VecRestoreArrayWrite(v, &x)); 3149 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3150 PetscFunctionReturn(PETSC_SUCCESS); 3151 } 3152 3153 static PetscErrorCode MatGetRowMax_SeqAIJ(Mat A, Vec v, PetscInt idx[]) 3154 { 3155 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3156 PetscInt i, j, m = A->rmap->n, *ai, *aj, ncols, n; 3157 PetscScalar *x; 3158 const MatScalar *aa, *av; 3159 3160 PetscFunctionBegin; 3161 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3162 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3163 aa = av; 3164 ai = a->i; 3165 aj = a->j; 3166 3167 PetscCall(VecGetArrayWrite(v, &x)); 3168 PetscCall(VecGetLocalSize(v, &n)); 3169 PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 3170 for (i = 0; i < m; i++) { 3171 ncols = ai[1] - ai[0]; 3172 ai++; 3173 if (ncols == A->cmap->n) { /* row is dense */ 3174 x[i] = *aa; 3175 if (idx) idx[i] = 0; 3176 } else { /* row is sparse so already KNOW maximum is 0.0 or higher */ 3177 x[i] = 0.0; 3178 if (idx) { 3179 for (j = 0; j < ncols; j++) { /* find first implicit 0.0 in the row */ 3180 if (aj[j] > j) { 3181 idx[i] = j; 3182 break; 3183 } 3184 } 3185 /* in case first implicit 0.0 in the row occurs at ncols-th column */ 3186 if (j == ncols && j < A->cmap->n) idx[i] = j; 3187 } 3188 } 3189 for (j = 0; j < ncols; j++) { 3190 if (PetscRealPart(x[i]) < PetscRealPart(*aa)) { 3191 x[i] = *aa; 3192 if (idx) idx[i] = *aj; 3193 } 3194 aa++; 3195 aj++; 3196 } 3197 } 3198 PetscCall(VecRestoreArrayWrite(v, &x)); 3199 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3200 PetscFunctionReturn(PETSC_SUCCESS); 3201 } 3202 3203 static PetscErrorCode MatGetRowMinAbs_SeqAIJ(Mat A, Vec v, PetscInt idx[]) 3204 { 3205 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3206 PetscInt i, j, m = A->rmap->n, *ai, *aj, ncols, n; 3207 PetscScalar *x; 3208 const MatScalar *aa, *av; 3209 3210 PetscFunctionBegin; 3211 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3212 aa = av; 3213 ai = a->i; 3214 aj = a->j; 3215 3216 PetscCall(VecGetArrayWrite(v, &x)); 3217 PetscCall(VecGetLocalSize(v, &n)); 3218 PetscCheck(n == m, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector, %" PetscInt_FMT " vs. %" PetscInt_FMT " rows", m, n); 3219 for (i = 0; i < m; i++) { 3220 ncols = ai[1] - ai[0]; 3221 ai++; 3222 if (ncols == A->cmap->n) { /* row is dense */ 3223 x[i] = *aa; 3224 if (idx) idx[i] = 0; 3225 } else { /* row is sparse so already KNOW minimum is 0.0 or higher */ 3226 x[i] = 0.0; 3227 if (idx) { /* find first implicit 0.0 in the row */ 3228 for (j = 0; j < ncols; j++) { 3229 if (aj[j] > j) { 3230 idx[i] = j; 3231 break; 3232 } 3233 } 3234 /* in case first implicit 0.0 in the row occurs at ncols-th column */ 3235 if (j == ncols && j < A->cmap->n) idx[i] = j; 3236 } 3237 } 3238 for (j = 0; j < ncols; j++) { 3239 if (PetscAbsScalar(x[i]) > PetscAbsScalar(*aa)) { 3240 x[i] = *aa; 3241 if (idx) idx[i] = *aj; 3242 } 3243 aa++; 3244 aj++; 3245 } 3246 } 3247 PetscCall(VecRestoreArrayWrite(v, &x)); 3248 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3249 PetscFunctionReturn(PETSC_SUCCESS); 3250 } 3251 3252 static PetscErrorCode MatGetRowMin_SeqAIJ(Mat A, Vec v, PetscInt idx[]) 3253 { 3254 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3255 PetscInt i, j, m = A->rmap->n, ncols, n; 3256 const PetscInt *ai, *aj; 3257 PetscScalar *x; 3258 const MatScalar *aa, *av; 3259 3260 PetscFunctionBegin; 3261 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3262 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3263 aa = av; 3264 ai = a->i; 3265 aj = a->j; 3266 3267 PetscCall(VecGetArrayWrite(v, &x)); 3268 PetscCall(VecGetLocalSize(v, &n)); 3269 PetscCheck(n == m, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 3270 for (i = 0; i < m; i++) { 3271 ncols = ai[1] - ai[0]; 3272 ai++; 3273 if (ncols == A->cmap->n) { /* row is dense */ 3274 x[i] = *aa; 3275 if (idx) idx[i] = 0; 3276 } else { /* row is sparse so already KNOW minimum is 0.0 or lower */ 3277 x[i] = 0.0; 3278 if (idx) { /* find first implicit 0.0 in the row */ 3279 for (j = 0; j < ncols; j++) { 3280 if (aj[j] > j) { 3281 idx[i] = j; 3282 break; 3283 } 3284 } 3285 /* in case first implicit 0.0 in the row occurs at ncols-th column */ 3286 if (j == ncols && j < A->cmap->n) idx[i] = j; 3287 } 3288 } 3289 for (j = 0; j < ncols; j++) { 3290 if (PetscRealPart(x[i]) > PetscRealPart(*aa)) { 3291 x[i] = *aa; 3292 if (idx) idx[i] = *aj; 3293 } 3294 aa++; 3295 aj++; 3296 } 3297 } 3298 PetscCall(VecRestoreArrayWrite(v, &x)); 3299 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3300 PetscFunctionReturn(PETSC_SUCCESS); 3301 } 3302 3303 static PetscErrorCode MatInvertBlockDiagonal_SeqAIJ(Mat A, const PetscScalar **values) 3304 { 3305 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3306 PetscInt i, bs = A->rmap->bs, mbs = A->rmap->n / bs, ipvt[5], bs2 = bs * bs, *v_pivots, ij[7], *IJ, j; 3307 MatScalar *diag, work[25], *v_work; 3308 const PetscReal shift = 0.0; 3309 PetscBool allowzeropivot, zeropivotdetected = PETSC_FALSE; 3310 3311 PetscFunctionBegin; 3312 allowzeropivot = PetscNot(A->erroriffailure); 3313 if (a->ibdiagvalid) { 3314 if (values) *values = a->ibdiag; 3315 PetscFunctionReturn(PETSC_SUCCESS); 3316 } 3317 PetscCall(MatMarkDiagonal_SeqAIJ(A)); 3318 if (!a->ibdiag) { PetscCall(PetscMalloc1(bs2 * mbs, &a->ibdiag)); } 3319 diag = a->ibdiag; 3320 if (values) *values = a->ibdiag; 3321 /* factor and invert each block */ 3322 switch (bs) { 3323 case 1: 3324 for (i = 0; i < mbs; i++) { 3325 PetscCall(MatGetValues(A, 1, &i, 1, &i, diag + i)); 3326 if (PetscAbsScalar(diag[i] + shift) < PETSC_MACHINE_EPSILON) { 3327 if (allowzeropivot) { 3328 A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3329 A->factorerror_zeropivot_value = PetscAbsScalar(diag[i]); 3330 A->factorerror_zeropivot_row = i; 3331 PetscCall(PetscInfo(A, "Zero pivot, row %" PetscInt_FMT " pivot %g tolerance %g\n", i, (double)PetscAbsScalar(diag[i]), (double)PETSC_MACHINE_EPSILON)); 3332 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_MAT_LU_ZRPVT, "Zero pivot, row %" PetscInt_FMT " pivot %g tolerance %g", i, (double)PetscAbsScalar(diag[i]), (double)PETSC_MACHINE_EPSILON); 3333 } 3334 diag[i] = (PetscScalar)1.0 / (diag[i] + shift); 3335 } 3336 break; 3337 case 2: 3338 for (i = 0; i < mbs; i++) { 3339 ij[0] = 2 * i; 3340 ij[1] = 2 * i + 1; 3341 PetscCall(MatGetValues(A, 2, ij, 2, ij, diag)); 3342 PetscCall(PetscKernel_A_gets_inverse_A_2(diag, shift, allowzeropivot, &zeropivotdetected)); 3343 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3344 PetscCall(PetscKernel_A_gets_transpose_A_2(diag)); 3345 diag += 4; 3346 } 3347 break; 3348 case 3: 3349 for (i = 0; i < mbs; i++) { 3350 ij[0] = 3 * i; 3351 ij[1] = 3 * i + 1; 3352 ij[2] = 3 * i + 2; 3353 PetscCall(MatGetValues(A, 3, ij, 3, ij, diag)); 3354 PetscCall(PetscKernel_A_gets_inverse_A_3(diag, shift, allowzeropivot, &zeropivotdetected)); 3355 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3356 PetscCall(PetscKernel_A_gets_transpose_A_3(diag)); 3357 diag += 9; 3358 } 3359 break; 3360 case 4: 3361 for (i = 0; i < mbs; i++) { 3362 ij[0] = 4 * i; 3363 ij[1] = 4 * i + 1; 3364 ij[2] = 4 * i + 2; 3365 ij[3] = 4 * i + 3; 3366 PetscCall(MatGetValues(A, 4, ij, 4, ij, diag)); 3367 PetscCall(PetscKernel_A_gets_inverse_A_4(diag, shift, allowzeropivot, &zeropivotdetected)); 3368 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3369 PetscCall(PetscKernel_A_gets_transpose_A_4(diag)); 3370 diag += 16; 3371 } 3372 break; 3373 case 5: 3374 for (i = 0; i < mbs; i++) { 3375 ij[0] = 5 * i; 3376 ij[1] = 5 * i + 1; 3377 ij[2] = 5 * i + 2; 3378 ij[3] = 5 * i + 3; 3379 ij[4] = 5 * i + 4; 3380 PetscCall(MatGetValues(A, 5, ij, 5, ij, diag)); 3381 PetscCall(PetscKernel_A_gets_inverse_A_5(diag, ipvt, work, shift, allowzeropivot, &zeropivotdetected)); 3382 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3383 PetscCall(PetscKernel_A_gets_transpose_A_5(diag)); 3384 diag += 25; 3385 } 3386 break; 3387 case 6: 3388 for (i = 0; i < mbs; i++) { 3389 ij[0] = 6 * i; 3390 ij[1] = 6 * i + 1; 3391 ij[2] = 6 * i + 2; 3392 ij[3] = 6 * i + 3; 3393 ij[4] = 6 * i + 4; 3394 ij[5] = 6 * i + 5; 3395 PetscCall(MatGetValues(A, 6, ij, 6, ij, diag)); 3396 PetscCall(PetscKernel_A_gets_inverse_A_6(diag, shift, allowzeropivot, &zeropivotdetected)); 3397 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3398 PetscCall(PetscKernel_A_gets_transpose_A_6(diag)); 3399 diag += 36; 3400 } 3401 break; 3402 case 7: 3403 for (i = 0; i < mbs; i++) { 3404 ij[0] = 7 * i; 3405 ij[1] = 7 * i + 1; 3406 ij[2] = 7 * i + 2; 3407 ij[3] = 7 * i + 3; 3408 ij[4] = 7 * i + 4; 3409 ij[5] = 7 * i + 5; 3410 ij[6] = 7 * i + 6; 3411 PetscCall(MatGetValues(A, 7, ij, 7, ij, diag)); 3412 PetscCall(PetscKernel_A_gets_inverse_A_7(diag, shift, allowzeropivot, &zeropivotdetected)); 3413 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3414 PetscCall(PetscKernel_A_gets_transpose_A_7(diag)); 3415 diag += 49; 3416 } 3417 break; 3418 default: 3419 PetscCall(PetscMalloc3(bs, &v_work, bs, &v_pivots, bs, &IJ)); 3420 for (i = 0; i < mbs; i++) { 3421 for (j = 0; j < bs; j++) IJ[j] = bs * i + j; 3422 PetscCall(MatGetValues(A, bs, IJ, bs, IJ, diag)); 3423 PetscCall(PetscKernel_A_gets_inverse_A(bs, diag, v_pivots, v_work, allowzeropivot, &zeropivotdetected)); 3424 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3425 PetscCall(PetscKernel_A_gets_transpose_A_N(diag, bs)); 3426 diag += bs2; 3427 } 3428 PetscCall(PetscFree3(v_work, v_pivots, IJ)); 3429 } 3430 a->ibdiagvalid = PETSC_TRUE; 3431 PetscFunctionReturn(PETSC_SUCCESS); 3432 } 3433 3434 static PetscErrorCode MatSetRandom_SeqAIJ(Mat x, PetscRandom rctx) 3435 { 3436 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)x->data; 3437 PetscScalar a, *aa; 3438 PetscInt m, n, i, j, col; 3439 3440 PetscFunctionBegin; 3441 if (!x->assembled) { 3442 PetscCall(MatGetSize(x, &m, &n)); 3443 for (i = 0; i < m; i++) { 3444 for (j = 0; j < aij->imax[i]; j++) { 3445 PetscCall(PetscRandomGetValue(rctx, &a)); 3446 col = (PetscInt)(n * PetscRealPart(a)); 3447 PetscCall(MatSetValues(x, 1, &i, 1, &col, &a, ADD_VALUES)); 3448 } 3449 } 3450 } else { 3451 PetscCall(MatSeqAIJGetArrayWrite(x, &aa)); 3452 for (i = 0; i < aij->nz; i++) PetscCall(PetscRandomGetValue(rctx, aa + i)); 3453 PetscCall(MatSeqAIJRestoreArrayWrite(x, &aa)); 3454 } 3455 PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY)); 3456 PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY)); 3457 PetscFunctionReturn(PETSC_SUCCESS); 3458 } 3459 3460 /* Like MatSetRandom_SeqAIJ, but do not set values on columns in range of [low, high) */ 3461 PetscErrorCode MatSetRandomSkipColumnRange_SeqAIJ_Private(Mat x, PetscInt low, PetscInt high, PetscRandom rctx) 3462 { 3463 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)x->data; 3464 PetscScalar a; 3465 PetscInt m, n, i, j, col, nskip; 3466 3467 PetscFunctionBegin; 3468 nskip = high - low; 3469 PetscCall(MatGetSize(x, &m, &n)); 3470 n -= nskip; /* shrink number of columns where nonzeros can be set */ 3471 for (i = 0; i < m; i++) { 3472 for (j = 0; j < aij->imax[i]; j++) { 3473 PetscCall(PetscRandomGetValue(rctx, &a)); 3474 col = (PetscInt)(n * PetscRealPart(a)); 3475 if (col >= low) col += nskip; /* shift col rightward to skip the hole */ 3476 PetscCall(MatSetValues(x, 1, &i, 1, &col, &a, ADD_VALUES)); 3477 } 3478 } 3479 PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY)); 3480 PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY)); 3481 PetscFunctionReturn(PETSC_SUCCESS); 3482 } 3483 3484 static struct _MatOps MatOps_Values = {MatSetValues_SeqAIJ, 3485 MatGetRow_SeqAIJ, 3486 MatRestoreRow_SeqAIJ, 3487 MatMult_SeqAIJ, 3488 /* 4*/ MatMultAdd_SeqAIJ, 3489 MatMultTranspose_SeqAIJ, 3490 MatMultTransposeAdd_SeqAIJ, 3491 NULL, 3492 NULL, 3493 NULL, 3494 /* 10*/ NULL, 3495 MatLUFactor_SeqAIJ, 3496 NULL, 3497 MatSOR_SeqAIJ, 3498 MatTranspose_SeqAIJ, 3499 /* 15*/ MatGetInfo_SeqAIJ, 3500 MatEqual_SeqAIJ, 3501 MatGetDiagonal_SeqAIJ, 3502 MatDiagonalScale_SeqAIJ, 3503 MatNorm_SeqAIJ, 3504 /* 20*/ NULL, 3505 MatAssemblyEnd_SeqAIJ, 3506 MatSetOption_SeqAIJ, 3507 MatZeroEntries_SeqAIJ, 3508 /* 24*/ MatZeroRows_SeqAIJ, 3509 NULL, 3510 NULL, 3511 NULL, 3512 NULL, 3513 /* 29*/ MatSetUp_Seq_Hash, 3514 NULL, 3515 NULL, 3516 NULL, 3517 NULL, 3518 /* 34*/ MatDuplicate_SeqAIJ, 3519 NULL, 3520 NULL, 3521 MatILUFactor_SeqAIJ, 3522 NULL, 3523 /* 39*/ MatAXPY_SeqAIJ, 3524 MatCreateSubMatrices_SeqAIJ, 3525 MatIncreaseOverlap_SeqAIJ, 3526 MatGetValues_SeqAIJ, 3527 MatCopy_SeqAIJ, 3528 /* 44*/ MatGetRowMax_SeqAIJ, 3529 MatScale_SeqAIJ, 3530 MatShift_SeqAIJ, 3531 MatDiagonalSet_SeqAIJ, 3532 MatZeroRowsColumns_SeqAIJ, 3533 /* 49*/ MatSetRandom_SeqAIJ, 3534 MatGetRowIJ_SeqAIJ, 3535 MatRestoreRowIJ_SeqAIJ, 3536 MatGetColumnIJ_SeqAIJ, 3537 MatRestoreColumnIJ_SeqAIJ, 3538 /* 54*/ MatFDColoringCreate_SeqXAIJ, 3539 NULL, 3540 NULL, 3541 MatPermute_SeqAIJ, 3542 NULL, 3543 /* 59*/ NULL, 3544 MatDestroy_SeqAIJ, 3545 MatView_SeqAIJ, 3546 NULL, 3547 NULL, 3548 /* 64*/ MatMatMatMultNumeric_SeqAIJ_SeqAIJ_SeqAIJ, 3549 NULL, 3550 NULL, 3551 NULL, 3552 MatGetRowMaxAbs_SeqAIJ, 3553 /* 69*/ MatGetRowMinAbs_SeqAIJ, 3554 NULL, 3555 NULL, 3556 MatFDColoringApply_AIJ, 3557 NULL, 3558 /* 74*/ MatFindZeroDiagonals_SeqAIJ, 3559 NULL, 3560 NULL, 3561 NULL, 3562 MatLoad_SeqAIJ, 3563 /* 79*/ NULL, 3564 NULL, 3565 NULL, 3566 NULL, 3567 NULL, 3568 /* 84*/ NULL, 3569 MatMatMultNumeric_SeqAIJ_SeqAIJ, 3570 MatPtAPNumeric_SeqAIJ_SeqAIJ_SparseAxpy, 3571 NULL, 3572 MatMatTransposeMultNumeric_SeqAIJ_SeqAIJ, 3573 /* 90*/ NULL, 3574 MatProductSetFromOptions_SeqAIJ, 3575 NULL, 3576 NULL, 3577 MatConjugate_SeqAIJ, 3578 /* 94*/ NULL, 3579 MatSetValuesRow_SeqAIJ, 3580 MatRealPart_SeqAIJ, 3581 MatImaginaryPart_SeqAIJ, 3582 NULL, 3583 /* 99*/ NULL, 3584 MatMatSolve_SeqAIJ, 3585 NULL, 3586 MatGetRowMin_SeqAIJ, 3587 NULL, 3588 /*104*/ MatMissingDiagonal_SeqAIJ, 3589 NULL, 3590 NULL, 3591 NULL, 3592 NULL, 3593 /*109*/ NULL, 3594 NULL, 3595 NULL, 3596 NULL, 3597 NULL, 3598 /*114*/ MatGetMultiProcBlock_SeqAIJ, 3599 MatFindNonzeroRows_SeqAIJ, 3600 MatGetColumnReductions_SeqAIJ, 3601 MatInvertBlockDiagonal_SeqAIJ, 3602 MatInvertVariableBlockDiagonal_SeqAIJ, 3603 /*119*/ NULL, 3604 NULL, 3605 NULL, 3606 MatTransposeMatMultNumeric_SeqAIJ_SeqAIJ, 3607 MatTransposeColoringCreate_SeqAIJ, 3608 /*124*/ MatTransColoringApplySpToDen_SeqAIJ, 3609 MatTransColoringApplyDenToSp_SeqAIJ, 3610 MatRARtNumeric_SeqAIJ_SeqAIJ, 3611 NULL, 3612 NULL, 3613 /*129*/ MatFDColoringSetUp_SeqXAIJ, 3614 MatFindOffBlockDiagonalEntries_SeqAIJ, 3615 MatCreateMPIMatConcatenateSeqMat_SeqAIJ, 3616 MatDestroySubMatrices_SeqAIJ, 3617 NULL, 3618 /*134*/ NULL, 3619 MatCreateGraph_Simple_AIJ, 3620 MatTransposeSymbolic_SeqAIJ, 3621 MatEliminateZeros_SeqAIJ, 3622 MatGetRowSumAbs_SeqAIJ, 3623 /*139*/ NULL, 3624 NULL, 3625 NULL, 3626 MatCopyHashToXAIJ_Seq_Hash}; 3627 3628 static PetscErrorCode MatSeqAIJSetColumnIndices_SeqAIJ(Mat mat, PetscInt *indices) 3629 { 3630 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3631 PetscInt i, nz, n; 3632 3633 PetscFunctionBegin; 3634 nz = aij->maxnz; 3635 n = mat->rmap->n; 3636 for (i = 0; i < nz; i++) aij->j[i] = indices[i]; 3637 aij->nz = nz; 3638 for (i = 0; i < n; i++) aij->ilen[i] = aij->imax[i]; 3639 PetscFunctionReturn(PETSC_SUCCESS); 3640 } 3641 3642 /* 3643 * Given a sparse matrix with global column indices, compact it by using a local column space. 3644 * The result matrix helps saving memory in other algorithms, such as MatPtAPSymbolic_MPIAIJ_MPIAIJ_scalable() 3645 */ 3646 PetscErrorCode MatSeqAIJCompactOutExtraColumns_SeqAIJ(Mat mat, ISLocalToGlobalMapping *mapping) 3647 { 3648 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3649 PetscHMapI gid1_lid1; 3650 PetscHashIter tpos; 3651 PetscInt gid, lid, i, ec, nz = aij->nz; 3652 PetscInt *garray, *jj = aij->j; 3653 3654 PetscFunctionBegin; 3655 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3656 PetscAssertPointer(mapping, 2); 3657 /* use a table */ 3658 PetscCall(PetscHMapICreateWithSize(mat->rmap->n, &gid1_lid1)); 3659 ec = 0; 3660 for (i = 0; i < nz; i++) { 3661 PetscInt data, gid1 = jj[i] + 1; 3662 PetscCall(PetscHMapIGetWithDefault(gid1_lid1, gid1, 0, &data)); 3663 if (!data) { 3664 /* one based table */ 3665 PetscCall(PetscHMapISet(gid1_lid1, gid1, ++ec)); 3666 } 3667 } 3668 /* form array of columns we need */ 3669 PetscCall(PetscMalloc1(ec, &garray)); 3670 PetscHashIterBegin(gid1_lid1, tpos); 3671 while (!PetscHashIterAtEnd(gid1_lid1, tpos)) { 3672 PetscHashIterGetKey(gid1_lid1, tpos, gid); 3673 PetscHashIterGetVal(gid1_lid1, tpos, lid); 3674 PetscHashIterNext(gid1_lid1, tpos); 3675 gid--; 3676 lid--; 3677 garray[lid] = gid; 3678 } 3679 PetscCall(PetscSortInt(ec, garray)); /* sort, and rebuild */ 3680 PetscCall(PetscHMapIClear(gid1_lid1)); 3681 for (i = 0; i < ec; i++) PetscCall(PetscHMapISet(gid1_lid1, garray[i] + 1, i + 1)); 3682 /* compact out the extra columns in B */ 3683 for (i = 0; i < nz; i++) { 3684 PetscInt gid1 = jj[i] + 1; 3685 PetscCall(PetscHMapIGetWithDefault(gid1_lid1, gid1, 0, &lid)); 3686 lid--; 3687 jj[i] = lid; 3688 } 3689 PetscCall(PetscLayoutDestroy(&mat->cmap)); 3690 PetscCall(PetscHMapIDestroy(&gid1_lid1)); 3691 PetscCall(PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)mat), ec, ec, 1, &mat->cmap)); 3692 PetscCall(ISLocalToGlobalMappingCreate(PETSC_COMM_SELF, mat->cmap->bs, mat->cmap->n, garray, PETSC_OWN_POINTER, mapping)); 3693 PetscCall(ISLocalToGlobalMappingSetType(*mapping, ISLOCALTOGLOBALMAPPINGHASH)); 3694 PetscFunctionReturn(PETSC_SUCCESS); 3695 } 3696 3697 /*@ 3698 MatSeqAIJSetColumnIndices - Set the column indices for all the rows 3699 in the matrix. 3700 3701 Input Parameters: 3702 + mat - the `MATSEQAIJ` matrix 3703 - indices - the column indices 3704 3705 Level: advanced 3706 3707 Notes: 3708 This can be called if you have precomputed the nonzero structure of the 3709 matrix and want to provide it to the matrix object to improve the performance 3710 of the `MatSetValues()` operation. 3711 3712 You MUST have set the correct numbers of nonzeros per row in the call to 3713 `MatCreateSeqAIJ()`, and the columns indices MUST be sorted. 3714 3715 MUST be called before any calls to `MatSetValues()` 3716 3717 The indices should start with zero, not one. 3718 3719 .seealso: [](ch_matrices), `Mat`, `MATSEQAIJ` 3720 @*/ 3721 PetscErrorCode MatSeqAIJSetColumnIndices(Mat mat, PetscInt *indices) 3722 { 3723 PetscFunctionBegin; 3724 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3725 PetscAssertPointer(indices, 2); 3726 PetscUseMethod(mat, "MatSeqAIJSetColumnIndices_C", (Mat, PetscInt *), (mat, indices)); 3727 PetscFunctionReturn(PETSC_SUCCESS); 3728 } 3729 3730 static PetscErrorCode MatStoreValues_SeqAIJ(Mat mat) 3731 { 3732 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3733 size_t nz = aij->i[mat->rmap->n]; 3734 3735 PetscFunctionBegin; 3736 PetscCheck(aij->nonew, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first"); 3737 3738 /* allocate space for values if not already there */ 3739 if (!aij->saved_values) { PetscCall(PetscMalloc1(nz + 1, &aij->saved_values)); } 3740 3741 /* copy values over */ 3742 PetscCall(PetscArraycpy(aij->saved_values, aij->a, nz)); 3743 PetscFunctionReturn(PETSC_SUCCESS); 3744 } 3745 3746 /*@ 3747 MatStoreValues - Stashes a copy of the matrix values; this allows reusing of the linear part of a Jacobian, while recomputing only the 3748 nonlinear portion. 3749 3750 Logically Collect 3751 3752 Input Parameter: 3753 . mat - the matrix (currently only `MATAIJ` matrices support this option) 3754 3755 Level: advanced 3756 3757 Example Usage: 3758 .vb 3759 Using SNES 3760 Create Jacobian matrix 3761 Set linear terms into matrix 3762 Apply boundary conditions to matrix, at this time matrix must have 3763 final nonzero structure (i.e. setting the nonlinear terms and applying 3764 boundary conditions again will not change the nonzero structure 3765 MatSetOption(mat, MAT_NEW_NONZERO_LOCATIONS, PETSC_FALSE); 3766 MatStoreValues(mat); 3767 Call SNESSetJacobian() with matrix 3768 In your Jacobian routine 3769 MatRetrieveValues(mat); 3770 Set nonlinear terms in matrix 3771 3772 Without `SNESSolve()`, i.e. when you handle nonlinear solve yourself: 3773 // build linear portion of Jacobian 3774 MatSetOption(mat, MAT_NEW_NONZERO_LOCATIONS, PETSC_FALSE); 3775 MatStoreValues(mat); 3776 loop over nonlinear iterations 3777 MatRetrieveValues(mat); 3778 // call MatSetValues(mat,...) to set nonliner portion of Jacobian 3779 // call MatAssemblyBegin/End() on matrix 3780 Solve linear system with Jacobian 3781 endloop 3782 .ve 3783 3784 Notes: 3785 Matrix must already be assembled before calling this routine 3786 Must set the matrix option `MatSetOption`(mat,`MAT_NEW_NONZERO_LOCATIONS`,`PETSC_FALSE`); before 3787 calling this routine. 3788 3789 When this is called multiple times it overwrites the previous set of stored values 3790 and does not allocated additional space. 3791 3792 .seealso: [](ch_matrices), `Mat`, `MatRetrieveValues()` 3793 @*/ 3794 PetscErrorCode MatStoreValues(Mat mat) 3795 { 3796 PetscFunctionBegin; 3797 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3798 PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 3799 PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3800 PetscUseMethod(mat, "MatStoreValues_C", (Mat), (mat)); 3801 PetscFunctionReturn(PETSC_SUCCESS); 3802 } 3803 3804 static PetscErrorCode MatRetrieveValues_SeqAIJ(Mat mat) 3805 { 3806 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3807 PetscInt nz = aij->i[mat->rmap->n]; 3808 3809 PetscFunctionBegin; 3810 PetscCheck(aij->nonew, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first"); 3811 PetscCheck(aij->saved_values, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatStoreValues(A);first"); 3812 /* copy values over */ 3813 PetscCall(PetscArraycpy(aij->a, aij->saved_values, nz)); 3814 PetscFunctionReturn(PETSC_SUCCESS); 3815 } 3816 3817 /*@ 3818 MatRetrieveValues - Retrieves the copy of the matrix values that was stored with `MatStoreValues()` 3819 3820 Logically Collect 3821 3822 Input Parameter: 3823 . mat - the matrix (currently only `MATAIJ` matrices support this option) 3824 3825 Level: advanced 3826 3827 .seealso: [](ch_matrices), `Mat`, `MatStoreValues()` 3828 @*/ 3829 PetscErrorCode MatRetrieveValues(Mat mat) 3830 { 3831 PetscFunctionBegin; 3832 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3833 PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 3834 PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3835 PetscUseMethod(mat, "MatRetrieveValues_C", (Mat), (mat)); 3836 PetscFunctionReturn(PETSC_SUCCESS); 3837 } 3838 3839 /*@ 3840 MatCreateSeqAIJ - Creates a sparse matrix in `MATSEQAIJ` (compressed row) format 3841 (the default parallel PETSc format). For good matrix assembly performance 3842 the user should preallocate the matrix storage by setting the parameter `nz` 3843 (or the array `nnz`). 3844 3845 Collective 3846 3847 Input Parameters: 3848 + comm - MPI communicator, set to `PETSC_COMM_SELF` 3849 . m - number of rows 3850 . n - number of columns 3851 . nz - number of nonzeros per row (same for all rows) 3852 - nnz - array containing the number of nonzeros in the various rows 3853 (possibly different for each row) or NULL 3854 3855 Output Parameter: 3856 . A - the matrix 3857 3858 Options Database Keys: 3859 + -mat_no_inode - Do not use inodes 3860 - -mat_inode_limit <limit> - Sets inode limit (max limit=5) 3861 3862 Level: intermediate 3863 3864 Notes: 3865 It is recommend to use `MatCreateFromOptions()` instead of this routine 3866 3867 If `nnz` is given then `nz` is ignored 3868 3869 The `MATSEQAIJ` format, also called 3870 compressed row storage, is fully compatible with standard Fortran 3871 storage. That is, the stored row and column indices can begin at 3872 either one (as in Fortran) or zero. 3873 3874 Specify the preallocated storage with either `nz` or `nnz` (not both). 3875 Set `nz` = `PETSC_DEFAULT` and `nnz` = `NULL` for PETSc to control dynamic memory 3876 allocation. 3877 3878 By default, this format uses inodes (identical nodes) when possible, to 3879 improve numerical efficiency of matrix-vector products and solves. We 3880 search for consecutive rows with the same nonzero structure, thereby 3881 reusing matrix information to achieve increased efficiency. 3882 3883 .seealso: [](ch_matrices), `Mat`, [Sparse Matrix Creation](sec_matsparse), `MatCreate()`, `MatCreateAIJ()`, `MatSetValues()`, `MatSeqAIJSetColumnIndices()`, `MatCreateSeqAIJWithArrays()` 3884 @*/ 3885 PetscErrorCode MatCreateSeqAIJ(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt nz, const PetscInt nnz[], Mat *A) 3886 { 3887 PetscFunctionBegin; 3888 PetscCall(MatCreate(comm, A)); 3889 PetscCall(MatSetSizes(*A, m, n, m, n)); 3890 PetscCall(MatSetType(*A, MATSEQAIJ)); 3891 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*A, nz, nnz)); 3892 PetscFunctionReturn(PETSC_SUCCESS); 3893 } 3894 3895 /*@ 3896 MatSeqAIJSetPreallocation - For good matrix assembly performance 3897 the user should preallocate the matrix storage by setting the parameter nz 3898 (or the array nnz). By setting these parameters accurately, performance 3899 during matrix assembly can be increased by more than a factor of 50. 3900 3901 Collective 3902 3903 Input Parameters: 3904 + B - The matrix 3905 . nz - number of nonzeros per row (same for all rows) 3906 - nnz - array containing the number of nonzeros in the various rows 3907 (possibly different for each row) or NULL 3908 3909 Options Database Keys: 3910 + -mat_no_inode - Do not use inodes 3911 - -mat_inode_limit <limit> - Sets inode limit (max limit=5) 3912 3913 Level: intermediate 3914 3915 Notes: 3916 If `nnz` is given then `nz` is ignored 3917 3918 The `MATSEQAIJ` format also called 3919 compressed row storage, is fully compatible with standard Fortran 3920 storage. That is, the stored row and column indices can begin at 3921 either one (as in Fortran) or zero. See the users' manual for details. 3922 3923 Specify the preallocated storage with either `nz` or `nnz` (not both). 3924 Set nz = `PETSC_DEFAULT` and `nnz` = `NULL` for PETSc to control dynamic memory 3925 allocation. 3926 3927 You can call `MatGetInfo()` to get information on how effective the preallocation was; 3928 for example the fields mallocs,nz_allocated,nz_used,nz_unneeded; 3929 You can also run with the option -info and look for messages with the string 3930 malloc in them to see if additional memory allocation was needed. 3931 3932 Developer Notes: 3933 Use nz of `MAT_SKIP_ALLOCATION` to not allocate any space for the matrix 3934 entries or columns indices 3935 3936 By default, this format uses inodes (identical nodes) when possible, to 3937 improve numerical efficiency of matrix-vector products and solves. We 3938 search for consecutive rows with the same nonzero structure, thereby 3939 reusing matrix information to achieve increased efficiency. 3940 3941 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateAIJ()`, `MatSetValues()`, `MatSeqAIJSetColumnIndices()`, `MatCreateSeqAIJWithArrays()`, `MatGetInfo()`, 3942 `MatSeqAIJSetTotalPreallocation()` 3943 @*/ 3944 PetscErrorCode MatSeqAIJSetPreallocation(Mat B, PetscInt nz, const PetscInt nnz[]) 3945 { 3946 PetscFunctionBegin; 3947 PetscValidHeaderSpecific(B, MAT_CLASSID, 1); 3948 PetscValidType(B, 1); 3949 PetscTryMethod(B, "MatSeqAIJSetPreallocation_C", (Mat, PetscInt, const PetscInt[]), (B, nz, nnz)); 3950 PetscFunctionReturn(PETSC_SUCCESS); 3951 } 3952 3953 PetscErrorCode MatSeqAIJSetPreallocation_SeqAIJ(Mat B, PetscInt nz, const PetscInt *nnz) 3954 { 3955 Mat_SeqAIJ *b = (Mat_SeqAIJ *)B->data; 3956 PetscBool skipallocation = PETSC_FALSE, realalloc = PETSC_FALSE; 3957 PetscInt i; 3958 3959 PetscFunctionBegin; 3960 if (B->hash_active) { 3961 B->ops[0] = b->cops; 3962 PetscCall(PetscHMapIJVDestroy(&b->ht)); 3963 PetscCall(PetscFree(b->dnz)); 3964 B->hash_active = PETSC_FALSE; 3965 } 3966 if (nz >= 0 || nnz) realalloc = PETSC_TRUE; 3967 if (nz == MAT_SKIP_ALLOCATION) { 3968 skipallocation = PETSC_TRUE; 3969 nz = 0; 3970 } 3971 PetscCall(PetscLayoutSetUp(B->rmap)); 3972 PetscCall(PetscLayoutSetUp(B->cmap)); 3973 3974 if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 5; 3975 PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nz cannot be less than 0: value %" PetscInt_FMT, nz); 3976 if (nnz) { 3977 for (i = 0; i < B->rmap->n; i++) { 3978 PetscCheck(nnz[i] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nnz cannot be less than 0: local row %" PetscInt_FMT " value %" PetscInt_FMT, i, nnz[i]); 3979 PetscCheck(nnz[i] <= B->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nnz cannot be greater than row length: local row %" PetscInt_FMT " value %" PetscInt_FMT " rowlength %" PetscInt_FMT, i, nnz[i], B->cmap->n); 3980 } 3981 } 3982 3983 B->preallocated = PETSC_TRUE; 3984 if (!skipallocation) { 3985 if (!b->imax) { PetscCall(PetscMalloc1(B->rmap->n, &b->imax)); } 3986 if (!b->ilen) { 3987 /* b->ilen will count nonzeros in each row so far. */ 3988 PetscCall(PetscCalloc1(B->rmap->n, &b->ilen)); 3989 } else { 3990 PetscCall(PetscMemzero(b->ilen, B->rmap->n * sizeof(PetscInt))); 3991 } 3992 if (!b->ipre) PetscCall(PetscMalloc1(B->rmap->n, &b->ipre)); 3993 if (!nnz) { 3994 if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 10; 3995 else if (nz < 0) nz = 1; 3996 nz = PetscMin(nz, B->cmap->n); 3997 for (i = 0; i < B->rmap->n; i++) b->imax[i] = nz; 3998 PetscCall(PetscIntMultError(nz, B->rmap->n, &nz)); 3999 } else { 4000 PetscInt64 nz64 = 0; 4001 for (i = 0; i < B->rmap->n; i++) { 4002 b->imax[i] = nnz[i]; 4003 nz64 += nnz[i]; 4004 } 4005 PetscCall(PetscIntCast(nz64, &nz)); 4006 } 4007 4008 /* allocate the matrix space */ 4009 PetscCall(MatSeqXAIJFreeAIJ(B, &b->a, &b->j, &b->i)); 4010 PetscCall(PetscShmgetAllocateArray(nz, sizeof(PetscInt), (void **)&b->j)); 4011 PetscCall(PetscShmgetAllocateArray(B->rmap->n + 1, sizeof(PetscInt), (void **)&b->i)); 4012 b->free_ij = PETSC_TRUE; 4013 if (B->structure_only) { 4014 b->free_a = PETSC_FALSE; 4015 } else { 4016 PetscCall(PetscShmgetAllocateArray(nz, sizeof(PetscScalar), (void **)&b->a)); 4017 b->free_a = PETSC_TRUE; 4018 } 4019 b->i[0] = 0; 4020 for (i = 1; i < B->rmap->n + 1; i++) b->i[i] = b->i[i - 1] + b->imax[i - 1]; 4021 } else { 4022 b->free_a = PETSC_FALSE; 4023 b->free_ij = PETSC_FALSE; 4024 } 4025 4026 if (b->ipre && nnz != b->ipre && b->imax) { 4027 /* reserve user-requested sparsity */ 4028 PetscCall(PetscArraycpy(b->ipre, b->imax, B->rmap->n)); 4029 } 4030 4031 b->nz = 0; 4032 b->maxnz = nz; 4033 B->info.nz_unneeded = (double)b->maxnz; 4034 if (realalloc) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 4035 B->was_assembled = PETSC_FALSE; 4036 B->assembled = PETSC_FALSE; 4037 /* We simply deem preallocation has changed nonzero state. Updating the state 4038 will give clients (like AIJKokkos) a chance to know something has happened. 4039 */ 4040 B->nonzerostate++; 4041 PetscFunctionReturn(PETSC_SUCCESS); 4042 } 4043 4044 PetscErrorCode MatResetPreallocation_SeqAIJ_Private(Mat A, PetscBool *memoryreset) 4045 { 4046 Mat_SeqAIJ *a; 4047 PetscInt i; 4048 PetscBool skipreset; 4049 4050 PetscFunctionBegin; 4051 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 4052 4053 PetscCheck(A->insertmode == NOT_SET_VALUES, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot reset preallocation after setting some values but not yet calling MatAssemblyBegin()/MatAssemblyEnd()"); 4054 if (A->num_ass == 0) PetscFunctionReturn(PETSC_SUCCESS); 4055 4056 /* Check local size. If zero, then return */ 4057 if (!A->rmap->n) PetscFunctionReturn(PETSC_SUCCESS); 4058 4059 a = (Mat_SeqAIJ *)A->data; 4060 /* if no saved info, we error out */ 4061 PetscCheck(a->ipre, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "No saved preallocation info "); 4062 4063 PetscCheck(a->i && a->imax && a->ilen, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Memory info is incomplete, and cannot reset preallocation "); 4064 4065 PetscCall(PetscArraycmp(a->ipre, a->ilen, A->rmap->n, &skipreset)); 4066 if (skipreset) PetscCall(MatZeroEntries(A)); 4067 else { 4068 PetscCall(PetscArraycpy(a->imax, a->ipre, A->rmap->n)); 4069 PetscCall(PetscArrayzero(a->ilen, A->rmap->n)); 4070 a->i[0] = 0; 4071 for (i = 1; i < A->rmap->n + 1; i++) a->i[i] = a->i[i - 1] + a->imax[i - 1]; 4072 A->preallocated = PETSC_TRUE; 4073 a->nz = 0; 4074 a->maxnz = a->i[A->rmap->n]; 4075 A->info.nz_unneeded = (double)a->maxnz; 4076 A->was_assembled = PETSC_FALSE; 4077 A->assembled = PETSC_FALSE; 4078 A->nonzerostate++; 4079 /* Log that the state of this object has changed; this will help guarantee that preconditioners get re-setup */ 4080 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 4081 } 4082 if (memoryreset) *memoryreset = (PetscBool)!skipreset; 4083 PetscFunctionReturn(PETSC_SUCCESS); 4084 } 4085 4086 static PetscErrorCode MatResetPreallocation_SeqAIJ(Mat A) 4087 { 4088 PetscFunctionBegin; 4089 PetscCall(MatResetPreallocation_SeqAIJ_Private(A, NULL)); 4090 PetscFunctionReturn(PETSC_SUCCESS); 4091 } 4092 4093 /*@ 4094 MatSeqAIJSetPreallocationCSR - Allocates memory for a sparse sequential matrix in `MATSEQAIJ` format. 4095 4096 Input Parameters: 4097 + B - the matrix 4098 . i - the indices into `j` for the start of each row (indices start with zero) 4099 . j - the column indices for each row (indices start with zero) these must be sorted for each row 4100 - v - optional values in the matrix, use `NULL` if not provided 4101 4102 Level: developer 4103 4104 Notes: 4105 The `i`,`j`,`v` values are COPIED with this routine; to avoid the copy use `MatCreateSeqAIJWithArrays()` 4106 4107 This routine may be called multiple times with different nonzero patterns (or the same nonzero pattern). The nonzero 4108 structure will be the union of all the previous nonzero structures. 4109 4110 Developer Notes: 4111 An optimization could be added to the implementation where it checks if the `i`, and `j` are identical to the current `i` and `j` and 4112 then just copies the `v` values directly with `PetscMemcpy()`. 4113 4114 This routine could also take a `PetscCopyMode` argument to allow sharing the values instead of always copying them. 4115 4116 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateSeqAIJ()`, `MatSetValues()`, `MatSeqAIJSetPreallocation()`, `MATSEQAIJ`, `MatResetPreallocation()` 4117 @*/ 4118 PetscErrorCode MatSeqAIJSetPreallocationCSR(Mat B, const PetscInt i[], const PetscInt j[], const PetscScalar v[]) 4119 { 4120 PetscFunctionBegin; 4121 PetscValidHeaderSpecific(B, MAT_CLASSID, 1); 4122 PetscValidType(B, 1); 4123 PetscTryMethod(B, "MatSeqAIJSetPreallocationCSR_C", (Mat, const PetscInt[], const PetscInt[], const PetscScalar[]), (B, i, j, v)); 4124 PetscFunctionReturn(PETSC_SUCCESS); 4125 } 4126 4127 static PetscErrorCode MatSeqAIJSetPreallocationCSR_SeqAIJ(Mat B, const PetscInt Ii[], const PetscInt J[], const PetscScalar v[]) 4128 { 4129 PetscInt i; 4130 PetscInt m, n; 4131 PetscInt nz; 4132 PetscInt *nnz; 4133 4134 PetscFunctionBegin; 4135 PetscCheck(Ii[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Ii[0] must be 0 it is %" PetscInt_FMT, Ii[0]); 4136 4137 PetscCall(PetscLayoutSetUp(B->rmap)); 4138 PetscCall(PetscLayoutSetUp(B->cmap)); 4139 4140 PetscCall(MatGetSize(B, &m, &n)); 4141 PetscCall(PetscMalloc1(m + 1, &nnz)); 4142 for (i = 0; i < m; i++) { 4143 nz = Ii[i + 1] - Ii[i]; 4144 PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local row %" PetscInt_FMT " has a negative number of columns %" PetscInt_FMT, i, nz); 4145 nnz[i] = nz; 4146 } 4147 PetscCall(MatSeqAIJSetPreallocation(B, 0, nnz)); 4148 PetscCall(PetscFree(nnz)); 4149 4150 for (i = 0; i < m; i++) PetscCall(MatSetValues_SeqAIJ(B, 1, &i, Ii[i + 1] - Ii[i], J + Ii[i], PetscSafePointerPlusOffset(v, Ii[i]), INSERT_VALUES)); 4151 4152 PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY)); 4153 PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY)); 4154 4155 PetscCall(MatSetOption(B, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE)); 4156 PetscFunctionReturn(PETSC_SUCCESS); 4157 } 4158 4159 /*@ 4160 MatSeqAIJKron - Computes `C`, the Kronecker product of `A` and `B`. 4161 4162 Input Parameters: 4163 + A - left-hand side matrix 4164 . B - right-hand side matrix 4165 - reuse - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX` 4166 4167 Output Parameter: 4168 . C - Kronecker product of `A` and `B` 4169 4170 Level: intermediate 4171 4172 Note: 4173 `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the product matrix has not changed from that last call to `MatSeqAIJKron()`. 4174 4175 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MATKAIJ`, `MatReuse` 4176 @*/ 4177 PetscErrorCode MatSeqAIJKron(Mat A, Mat B, MatReuse reuse, Mat *C) 4178 { 4179 PetscFunctionBegin; 4180 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 4181 PetscValidType(A, 1); 4182 PetscValidHeaderSpecific(B, MAT_CLASSID, 2); 4183 PetscValidType(B, 2); 4184 PetscAssertPointer(C, 4); 4185 if (reuse == MAT_REUSE_MATRIX) { 4186 PetscValidHeaderSpecific(*C, MAT_CLASSID, 4); 4187 PetscValidType(*C, 4); 4188 } 4189 PetscTryMethod(A, "MatSeqAIJKron_C", (Mat, Mat, MatReuse, Mat *), (A, B, reuse, C)); 4190 PetscFunctionReturn(PETSC_SUCCESS); 4191 } 4192 4193 static PetscErrorCode MatSeqAIJKron_SeqAIJ(Mat A, Mat B, MatReuse reuse, Mat *C) 4194 { 4195 Mat newmat; 4196 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 4197 Mat_SeqAIJ *b = (Mat_SeqAIJ *)B->data; 4198 PetscScalar *v; 4199 const PetscScalar *aa, *ba; 4200 PetscInt *i, *j, m, n, p, q, nnz = 0, am = A->rmap->n, bm = B->rmap->n, an = A->cmap->n, bn = B->cmap->n; 4201 PetscBool flg; 4202 4203 PetscFunctionBegin; 4204 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 4205 PetscCheck(A->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 4206 PetscCheck(!B->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 4207 PetscCheck(B->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 4208 PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &flg)); 4209 PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatType %s", ((PetscObject)B)->type_name); 4210 PetscCheck(reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatReuse %d", (int)reuse); 4211 if (reuse == MAT_INITIAL_MATRIX) { 4212 PetscCall(PetscMalloc2(am * bm + 1, &i, a->i[am] * b->i[bm], &j)); 4213 PetscCall(MatCreate(PETSC_COMM_SELF, &newmat)); 4214 PetscCall(MatSetSizes(newmat, am * bm, an * bn, am * bm, an * bn)); 4215 PetscCall(MatSetType(newmat, MATAIJ)); 4216 i[0] = 0; 4217 for (m = 0; m < am; ++m) { 4218 for (p = 0; p < bm; ++p) { 4219 i[m * bm + p + 1] = i[m * bm + p] + (a->i[m + 1] - a->i[m]) * (b->i[p + 1] - b->i[p]); 4220 for (n = a->i[m]; n < a->i[m + 1]; ++n) { 4221 for (q = b->i[p]; q < b->i[p + 1]; ++q) j[nnz++] = a->j[n] * bn + b->j[q]; 4222 } 4223 } 4224 } 4225 PetscCall(MatSeqAIJSetPreallocationCSR(newmat, i, j, NULL)); 4226 *C = newmat; 4227 PetscCall(PetscFree2(i, j)); 4228 nnz = 0; 4229 } 4230 PetscCall(MatSeqAIJGetArray(*C, &v)); 4231 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 4232 PetscCall(MatSeqAIJGetArrayRead(B, &ba)); 4233 for (m = 0; m < am; ++m) { 4234 for (p = 0; p < bm; ++p) { 4235 for (n = a->i[m]; n < a->i[m + 1]; ++n) { 4236 for (q = b->i[p]; q < b->i[p + 1]; ++q) v[nnz++] = aa[n] * ba[q]; 4237 } 4238 } 4239 } 4240 PetscCall(MatSeqAIJRestoreArray(*C, &v)); 4241 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 4242 PetscCall(MatSeqAIJRestoreArrayRead(B, &ba)); 4243 PetscFunctionReturn(PETSC_SUCCESS); 4244 } 4245 4246 #include <../src/mat/impls/dense/seq/dense.h> 4247 #include <petsc/private/kernels/petscaxpy.h> 4248 4249 /* 4250 Computes (B'*A')' since computing B*A directly is untenable 4251 4252 n p p 4253 [ ] [ ] [ ] 4254 m [ A ] * n [ B ] = m [ C ] 4255 [ ] [ ] [ ] 4256 4257 */ 4258 PetscErrorCode MatMatMultNumeric_SeqDense_SeqAIJ(Mat A, Mat B, Mat C) 4259 { 4260 Mat_SeqDense *sub_a = (Mat_SeqDense *)A->data; 4261 Mat_SeqAIJ *sub_b = (Mat_SeqAIJ *)B->data; 4262 Mat_SeqDense *sub_c = (Mat_SeqDense *)C->data; 4263 PetscInt i, j, n, m, q, p; 4264 const PetscInt *ii, *idx; 4265 const PetscScalar *b, *a, *a_q; 4266 PetscScalar *c, *c_q; 4267 PetscInt clda = sub_c->lda; 4268 PetscInt alda = sub_a->lda; 4269 4270 PetscFunctionBegin; 4271 m = A->rmap->n; 4272 n = A->cmap->n; 4273 p = B->cmap->n; 4274 a = sub_a->v; 4275 b = sub_b->a; 4276 c = sub_c->v; 4277 if (clda == m) { 4278 PetscCall(PetscArrayzero(c, m * p)); 4279 } else { 4280 for (j = 0; j < p; j++) 4281 for (i = 0; i < m; i++) c[j * clda + i] = 0.0; 4282 } 4283 ii = sub_b->i; 4284 idx = sub_b->j; 4285 for (i = 0; i < n; i++) { 4286 q = ii[i + 1] - ii[i]; 4287 while (q-- > 0) { 4288 c_q = c + clda * (*idx); 4289 a_q = a + alda * i; 4290 PetscKernelAXPY(c_q, *b, a_q, m); 4291 idx++; 4292 b++; 4293 } 4294 } 4295 PetscFunctionReturn(PETSC_SUCCESS); 4296 } 4297 4298 PetscErrorCode MatMatMultSymbolic_SeqDense_SeqAIJ(Mat A, Mat B, PetscReal fill, Mat C) 4299 { 4300 PetscInt m = A->rmap->n, n = B->cmap->n; 4301 PetscBool cisdense; 4302 4303 PetscFunctionBegin; 4304 PetscCheck(A->cmap->n == B->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "A->cmap->n %" PetscInt_FMT " != B->rmap->n %" PetscInt_FMT, A->cmap->n, B->rmap->n); 4305 PetscCall(MatSetSizes(C, m, n, m, n)); 4306 PetscCall(MatSetBlockSizesFromMats(C, A, B)); 4307 PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATSEQDENSECUDA, MATSEQDENSEHIP, "")); 4308 if (!cisdense) PetscCall(MatSetType(C, MATDENSE)); 4309 PetscCall(MatSetUp(C)); 4310 4311 C->ops->matmultnumeric = MatMatMultNumeric_SeqDense_SeqAIJ; 4312 PetscFunctionReturn(PETSC_SUCCESS); 4313 } 4314 4315 /*MC 4316 MATSEQAIJ - MATSEQAIJ = "seqaij" - A matrix type to be used for sequential sparse matrices, 4317 based on compressed sparse row format. 4318 4319 Options Database Key: 4320 . -mat_type seqaij - sets the matrix type to "seqaij" during a call to MatSetFromOptions() 4321 4322 Level: beginner 4323 4324 Notes: 4325 `MatSetValues()` may be called for this matrix type with a `NULL` argument for the numerical values, 4326 in this case the values associated with the rows and columns one passes in are set to zero 4327 in the matrix 4328 4329 `MatSetOptions`(,`MAT_STRUCTURE_ONLY`,`PETSC_TRUE`) may be called for this matrix type. In this no 4330 space is allocated for the nonzero entries and any entries passed with `MatSetValues()` are ignored 4331 4332 Developer Note: 4333 It would be nice if all matrix formats supported passing `NULL` in for the numerical values 4334 4335 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MatSetFromOptions()`, `MatSetType()`, `MatCreate()`, `MatType`, `MATSELL`, `MATSEQSELL`, `MATMPISELL` 4336 M*/ 4337 4338 /*MC 4339 MATAIJ - MATAIJ = "aij" - A matrix type to be used for sparse matrices. 4340 4341 This matrix type is identical to `MATSEQAIJ` when constructed with a single process communicator, 4342 and `MATMPIAIJ` otherwise. As a result, for single process communicators, 4343 `MatSeqAIJSetPreallocation()` is supported, and similarly `MatMPIAIJSetPreallocation()` is supported 4344 for communicators controlling multiple processes. It is recommended that you call both of 4345 the above preallocation routines for simplicity. 4346 4347 Options Database Key: 4348 . -mat_type aij - sets the matrix type to "aij" during a call to `MatSetFromOptions()` 4349 4350 Level: beginner 4351 4352 Note: 4353 Subclasses include `MATAIJCUSPARSE`, `MATAIJPERM`, `MATAIJSELL`, `MATAIJMKL`, `MATAIJCRL`, and also automatically switches over to use inodes when 4354 enough exist. 4355 4356 .seealso: [](ch_matrices), `Mat`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MATMPIAIJ`, `MATSELL`, `MATSEQSELL`, `MATMPISELL` 4357 M*/ 4358 4359 /*MC 4360 MATAIJCRL - MATAIJCRL = "aijcrl" - A matrix type to be used for sparse matrices. 4361 4362 Options Database Key: 4363 . -mat_type aijcrl - sets the matrix type to "aijcrl" during a call to `MatSetFromOptions()` 4364 4365 Level: beginner 4366 4367 Note: 4368 This matrix type is identical to `MATSEQAIJCRL` when constructed with a single process communicator, 4369 and `MATMPIAIJCRL` otherwise. As a result, for single process communicators, 4370 `MatSeqAIJSetPreallocation()` is supported, and similarly `MatMPIAIJSetPreallocation()` is supported 4371 for communicators controlling multiple processes. It is recommended that you call both of 4372 the above preallocation routines for simplicity. 4373 4374 .seealso: [](ch_matrices), `Mat`, `MatCreateMPIAIJCRL`, `MATSEQAIJCRL`, `MATMPIAIJCRL`, `MATSEQAIJCRL`, `MATMPIAIJCRL` 4375 M*/ 4376 4377 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJCRL(Mat, MatType, MatReuse, Mat *); 4378 #if defined(PETSC_HAVE_ELEMENTAL) 4379 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_Elemental(Mat, MatType, MatReuse, Mat *); 4380 #endif 4381 #if defined(PETSC_HAVE_SCALAPACK) 4382 PETSC_INTERN PetscErrorCode MatConvert_AIJ_ScaLAPACK(Mat, MatType, MatReuse, Mat *); 4383 #endif 4384 #if defined(PETSC_HAVE_HYPRE) 4385 PETSC_INTERN PetscErrorCode MatConvert_AIJ_HYPRE(Mat A, MatType, MatReuse, Mat *); 4386 #endif 4387 4388 PETSC_EXTERN PetscErrorCode MatConvert_SeqAIJ_SeqSELL(Mat, MatType, MatReuse, Mat *); 4389 PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat, MatType, MatReuse, Mat *); 4390 PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat); 4391 4392 /*@C 4393 MatSeqAIJGetArray - gives read/write access to the array where the data for a `MATSEQAIJ` matrix is stored 4394 4395 Not Collective 4396 4397 Input Parameter: 4398 . A - a `MATSEQAIJ` matrix 4399 4400 Output Parameter: 4401 . array - pointer to the data 4402 4403 Level: intermediate 4404 4405 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJRestoreArray()` 4406 @*/ 4407 PetscErrorCode MatSeqAIJGetArray(Mat A, PetscScalar *array[]) 4408 { 4409 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4410 4411 PetscFunctionBegin; 4412 if (aij->ops->getarray) { 4413 PetscCall((*aij->ops->getarray)(A, array)); 4414 } else { 4415 *array = aij->a; 4416 } 4417 PetscFunctionReturn(PETSC_SUCCESS); 4418 } 4419 4420 /*@C 4421 MatSeqAIJRestoreArray - returns access to the array where the data for a `MATSEQAIJ` matrix is stored obtained by `MatSeqAIJGetArray()` 4422 4423 Not Collective 4424 4425 Input Parameters: 4426 + A - a `MATSEQAIJ` matrix 4427 - array - pointer to the data 4428 4429 Level: intermediate 4430 4431 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()` 4432 @*/ 4433 PetscErrorCode MatSeqAIJRestoreArray(Mat A, PetscScalar *array[]) 4434 { 4435 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4436 4437 PetscFunctionBegin; 4438 if (aij->ops->restorearray) { 4439 PetscCall((*aij->ops->restorearray)(A, array)); 4440 } else { 4441 *array = NULL; 4442 } 4443 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 4444 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 4445 PetscFunctionReturn(PETSC_SUCCESS); 4446 } 4447 4448 /*@C 4449 MatSeqAIJGetArrayRead - gives read-only access to the array where the data for a `MATSEQAIJ` matrix is stored 4450 4451 Not Collective; No Fortran Support 4452 4453 Input Parameter: 4454 . A - a `MATSEQAIJ` matrix 4455 4456 Output Parameter: 4457 . array - pointer to the data 4458 4459 Level: intermediate 4460 4461 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayRead()` 4462 @*/ 4463 PetscErrorCode MatSeqAIJGetArrayRead(Mat A, const PetscScalar *array[]) 4464 { 4465 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4466 4467 PetscFunctionBegin; 4468 if (aij->ops->getarrayread) { 4469 PetscCall((*aij->ops->getarrayread)(A, array)); 4470 } else { 4471 *array = aij->a; 4472 } 4473 PetscFunctionReturn(PETSC_SUCCESS); 4474 } 4475 4476 /*@C 4477 MatSeqAIJRestoreArrayRead - restore the read-only access array obtained from `MatSeqAIJGetArrayRead()` 4478 4479 Not Collective; No Fortran Support 4480 4481 Input Parameter: 4482 . A - a `MATSEQAIJ` matrix 4483 4484 Output Parameter: 4485 . array - pointer to the data 4486 4487 Level: intermediate 4488 4489 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4490 @*/ 4491 PetscErrorCode MatSeqAIJRestoreArrayRead(Mat A, const PetscScalar *array[]) 4492 { 4493 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4494 4495 PetscFunctionBegin; 4496 if (aij->ops->restorearrayread) { 4497 PetscCall((*aij->ops->restorearrayread)(A, array)); 4498 } else { 4499 *array = NULL; 4500 } 4501 PetscFunctionReturn(PETSC_SUCCESS); 4502 } 4503 4504 /*@C 4505 MatSeqAIJGetArrayWrite - gives write-only access to the array where the data for a `MATSEQAIJ` matrix is stored 4506 4507 Not Collective; No Fortran Support 4508 4509 Input Parameter: 4510 . A - a `MATSEQAIJ` matrix 4511 4512 Output Parameter: 4513 . array - pointer to the data 4514 4515 Level: intermediate 4516 4517 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayRead()` 4518 @*/ 4519 PetscErrorCode MatSeqAIJGetArrayWrite(Mat A, PetscScalar *array[]) 4520 { 4521 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4522 4523 PetscFunctionBegin; 4524 if (aij->ops->getarraywrite) { 4525 PetscCall((*aij->ops->getarraywrite)(A, array)); 4526 } else { 4527 *array = aij->a; 4528 } 4529 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 4530 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 4531 PetscFunctionReturn(PETSC_SUCCESS); 4532 } 4533 4534 /*@C 4535 MatSeqAIJRestoreArrayWrite - restore the read-only access array obtained from MatSeqAIJGetArrayRead 4536 4537 Not Collective; No Fortran Support 4538 4539 Input Parameter: 4540 . A - a MATSEQAIJ matrix 4541 4542 Output Parameter: 4543 . array - pointer to the data 4544 4545 Level: intermediate 4546 4547 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4548 @*/ 4549 PetscErrorCode MatSeqAIJRestoreArrayWrite(Mat A, PetscScalar *array[]) 4550 { 4551 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4552 4553 PetscFunctionBegin; 4554 if (aij->ops->restorearraywrite) { 4555 PetscCall((*aij->ops->restorearraywrite)(A, array)); 4556 } else { 4557 *array = NULL; 4558 } 4559 PetscFunctionReturn(PETSC_SUCCESS); 4560 } 4561 4562 /*@C 4563 MatSeqAIJGetCSRAndMemType - Get the CSR arrays and the memory type of the `MATSEQAIJ` matrix 4564 4565 Not Collective; No Fortran Support 4566 4567 Input Parameter: 4568 . mat - a matrix of type `MATSEQAIJ` or its subclasses 4569 4570 Output Parameters: 4571 + i - row map array of the matrix 4572 . j - column index array of the matrix 4573 . a - data array of the matrix 4574 - mtype - memory type of the arrays 4575 4576 Level: developer 4577 4578 Notes: 4579 Any of the output parameters can be `NULL`, in which case the corresponding value is not returned. 4580 If mat is a device matrix, the arrays are on the device. Otherwise, they are on the host. 4581 4582 One can call this routine on a preallocated but not assembled matrix to just get the memory of the CSR underneath the matrix. 4583 If the matrix is assembled, the data array `a` is guaranteed to have the latest values of the matrix. 4584 4585 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4586 @*/ 4587 PetscErrorCode MatSeqAIJGetCSRAndMemType(Mat mat, const PetscInt *i[], const PetscInt *j[], PetscScalar *a[], PetscMemType *mtype) 4588 { 4589 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 4590 4591 PetscFunctionBegin; 4592 PetscCheck(mat->preallocated, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "matrix is not preallocated"); 4593 if (aij->ops->getcsrandmemtype) { 4594 PetscCall((*aij->ops->getcsrandmemtype)(mat, i, j, a, mtype)); 4595 } else { 4596 if (i) *i = aij->i; 4597 if (j) *j = aij->j; 4598 if (a) *a = aij->a; 4599 if (mtype) *mtype = PETSC_MEMTYPE_HOST; 4600 } 4601 PetscFunctionReturn(PETSC_SUCCESS); 4602 } 4603 4604 /*@ 4605 MatSeqAIJGetMaxRowNonzeros - returns the maximum number of nonzeros in any row 4606 4607 Not Collective 4608 4609 Input Parameter: 4610 . A - a `MATSEQAIJ` matrix 4611 4612 Output Parameter: 4613 . nz - the maximum number of nonzeros in any row 4614 4615 Level: intermediate 4616 4617 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJRestoreArray()` 4618 @*/ 4619 PetscErrorCode MatSeqAIJGetMaxRowNonzeros(Mat A, PetscInt *nz) 4620 { 4621 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4622 4623 PetscFunctionBegin; 4624 *nz = aij->rmax; 4625 PetscFunctionReturn(PETSC_SUCCESS); 4626 } 4627 4628 static PetscErrorCode MatCOOStructDestroy_SeqAIJ(void **data) 4629 { 4630 MatCOOStruct_SeqAIJ *coo = (MatCOOStruct_SeqAIJ *)*data; 4631 4632 PetscFunctionBegin; 4633 PetscCall(PetscFree(coo->perm)); 4634 PetscCall(PetscFree(coo->jmap)); 4635 PetscCall(PetscFree(coo)); 4636 PetscFunctionReturn(PETSC_SUCCESS); 4637 } 4638 4639 PetscErrorCode MatSetPreallocationCOO_SeqAIJ(Mat mat, PetscCount coo_n, PetscInt coo_i[], PetscInt coo_j[]) 4640 { 4641 MPI_Comm comm; 4642 PetscInt *i, *j; 4643 PetscInt M, N, row, iprev; 4644 PetscCount k, p, q, nneg, nnz, start, end; /* Index the coo array, so use PetscCount as their type */ 4645 PetscInt *Ai; /* Change to PetscCount once we use it for row pointers */ 4646 PetscInt *Aj; 4647 PetscScalar *Aa; 4648 Mat_SeqAIJ *seqaij = (Mat_SeqAIJ *)mat->data; 4649 MatType rtype; 4650 PetscCount *perm, *jmap; 4651 MatCOOStruct_SeqAIJ *coo; 4652 PetscBool isorted; 4653 PetscBool hypre; 4654 const char *name; 4655 4656 PetscFunctionBegin; 4657 PetscCall(PetscObjectGetComm((PetscObject)mat, &comm)); 4658 PetscCall(MatGetSize(mat, &M, &N)); 4659 i = coo_i; 4660 j = coo_j; 4661 PetscCall(PetscMalloc1(coo_n, &perm)); 4662 4663 /* Ignore entries with negative row or col indices; at the same time, check if i[] is already sorted (e.g., MatConvert_AlJ_HYPRE results in this case) */ 4664 isorted = PETSC_TRUE; 4665 iprev = PETSC_INT_MIN; 4666 for (k = 0; k < coo_n; k++) { 4667 if (j[k] < 0) i[k] = -1; 4668 if (isorted) { 4669 if (i[k] < iprev) isorted = PETSC_FALSE; 4670 else iprev = i[k]; 4671 } 4672 perm[k] = k; 4673 } 4674 4675 /* Sort by row if not already */ 4676 if (!isorted) PetscCall(PetscSortIntWithIntCountArrayPair(coo_n, i, j, perm)); 4677 PetscCheck(i == NULL || i[coo_n - 1] < M, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "COO row index %" PetscInt_FMT " is >= the matrix row size %" PetscInt_FMT, i[coo_n - 1], M); 4678 4679 /* Advance k to the first row with a non-negative index */ 4680 for (k = 0; k < coo_n; k++) 4681 if (i[k] >= 0) break; 4682 nneg = k; 4683 PetscCall(PetscMalloc1(coo_n - nneg + 1, &jmap)); /* +1 to make a CSR-like data structure. jmap[i] originally is the number of repeats for i-th nonzero */ 4684 nnz = 0; /* Total number of unique nonzeros to be counted */ 4685 jmap++; /* Inc jmap by 1 for convenience */ 4686 4687 PetscCall(PetscShmgetAllocateArray(M + 1, sizeof(PetscInt), (void **)&Ai)); /* CSR of A */ 4688 PetscCall(PetscArrayzero(Ai, M + 1)); 4689 PetscCall(PetscShmgetAllocateArray(coo_n - nneg, sizeof(PetscInt), (void **)&Aj)); /* We have at most coo_n-nneg unique nonzeros */ 4690 4691 PetscCall(PetscObjectGetName((PetscObject)mat, &name)); 4692 PetscCall(PetscStrcmp("_internal_COO_mat_for_hypre", name, &hypre)); 4693 4694 /* In each row, sort by column, then unique column indices to get row length */ 4695 Ai++; /* Inc by 1 for convenience */ 4696 q = 0; /* q-th unique nonzero, with q starting from 0 */ 4697 while (k < coo_n) { 4698 PetscBool strictly_sorted; // this row is strictly sorted? 4699 PetscInt jprev; 4700 4701 /* get [start,end) indices for this row; also check if cols in this row are strictly sorted */ 4702 row = i[k]; 4703 start = k; 4704 jprev = PETSC_INT_MIN; 4705 strictly_sorted = PETSC_TRUE; 4706 while (k < coo_n && i[k] == row) { 4707 if (strictly_sorted) { 4708 if (j[k] <= jprev) strictly_sorted = PETSC_FALSE; 4709 else jprev = j[k]; 4710 } 4711 k++; 4712 } 4713 end = k; 4714 4715 /* hack for HYPRE: swap min column to diag so that diagonal values will go first */ 4716 if (hypre) { 4717 PetscInt minj = PETSC_INT_MAX; 4718 PetscBool hasdiag = PETSC_FALSE; 4719 4720 if (strictly_sorted) { // fast path to swap the first and the diag 4721 PetscCount tmp; 4722 for (p = start; p < end; p++) { 4723 if (j[p] == row && p != start) { 4724 j[p] = j[start]; // swap j[], so that the diagonal value will go first (manipulated by perm[]) 4725 j[start] = row; 4726 tmp = perm[start]; 4727 perm[start] = perm[p]; // also swap perm[] so we can save the call to PetscSortIntWithCountArray() below 4728 perm[p] = tmp; 4729 break; 4730 } 4731 } 4732 } else { 4733 for (p = start; p < end; p++) { 4734 hasdiag = (PetscBool)(hasdiag || (j[p] == row)); 4735 minj = PetscMin(minj, j[p]); 4736 } 4737 4738 if (hasdiag) { 4739 for (p = start; p < end; p++) { 4740 if (j[p] == minj) j[p] = row; 4741 else if (j[p] == row) j[p] = minj; 4742 } 4743 } 4744 } 4745 } 4746 // sort by columns in a row. perm[] indicates their original order 4747 if (!strictly_sorted) PetscCall(PetscSortIntWithCountArray(end - start, j + start, perm + start)); 4748 PetscCheck(end == start || j[end - 1] < N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "COO column index %" PetscInt_FMT " is >= the matrix column size %" PetscInt_FMT, j[end - 1], N); 4749 4750 if (strictly_sorted) { // fast path to set Aj[], jmap[], Ai[], nnz, q 4751 for (p = start; p < end; p++, q++) { 4752 Aj[q] = j[p]; 4753 jmap[q] = 1; 4754 } 4755 PetscCall(PetscIntCast(end - start, Ai + row)); 4756 nnz += Ai[row]; // q is already advanced 4757 } else { 4758 /* Find number of unique col entries in this row */ 4759 Aj[q] = j[start]; /* Log the first nonzero in this row */ 4760 jmap[q] = 1; /* Number of repeats of this nonzero entry */ 4761 Ai[row] = 1; 4762 nnz++; 4763 4764 for (p = start + 1; p < end; p++) { /* Scan remaining nonzero in this row */ 4765 if (j[p] != j[p - 1]) { /* Meet a new nonzero */ 4766 q++; 4767 jmap[q] = 1; 4768 Aj[q] = j[p]; 4769 Ai[row]++; 4770 nnz++; 4771 } else { 4772 jmap[q]++; 4773 } 4774 } 4775 q++; /* Move to next row and thus next unique nonzero */ 4776 } 4777 } 4778 4779 Ai--; /* Back to the beginning of Ai[] */ 4780 for (k = 0; k < M; k++) Ai[k + 1] += Ai[k]; 4781 jmap--; // Back to the beginning of jmap[] 4782 jmap[0] = 0; 4783 for (k = 0; k < nnz; k++) jmap[k + 1] += jmap[k]; 4784 4785 if (nnz < coo_n - nneg) { /* Reallocate with actual number of unique nonzeros */ 4786 PetscCount *jmap_new; 4787 PetscInt *Aj_new; 4788 4789 PetscCall(PetscMalloc1(nnz + 1, &jmap_new)); 4790 PetscCall(PetscArraycpy(jmap_new, jmap, nnz + 1)); 4791 PetscCall(PetscFree(jmap)); 4792 jmap = jmap_new; 4793 4794 PetscCall(PetscShmgetAllocateArray(nnz, sizeof(PetscInt), (void **)&Aj_new)); 4795 PetscCall(PetscArraycpy(Aj_new, Aj, nnz)); 4796 PetscCall(PetscShmgetDeallocateArray((void **)&Aj)); 4797 Aj = Aj_new; 4798 } 4799 4800 if (nneg) { /* Discard heading entries with negative indices in perm[], as we'll access it from index 0 in MatSetValuesCOO */ 4801 PetscCount *perm_new; 4802 4803 PetscCall(PetscMalloc1(coo_n - nneg, &perm_new)); 4804 PetscCall(PetscArraycpy(perm_new, perm + nneg, coo_n - nneg)); 4805 PetscCall(PetscFree(perm)); 4806 perm = perm_new; 4807 } 4808 4809 PetscCall(MatGetRootType_Private(mat, &rtype)); 4810 PetscCall(PetscShmgetAllocateArray(nnz, sizeof(PetscScalar), (void **)&Aa)); 4811 PetscCall(PetscArrayzero(Aa, nnz)); 4812 PetscCall(MatSetSeqAIJWithArrays_private(PETSC_COMM_SELF, M, N, Ai, Aj, Aa, rtype, mat)); 4813 4814 seqaij->free_a = seqaij->free_ij = PETSC_TRUE; /* Let newmat own Ai, Aj and Aa */ 4815 4816 // Put the COO struct in a container and then attach that to the matrix 4817 PetscCall(PetscMalloc1(1, &coo)); 4818 PetscCall(PetscIntCast(nnz, &coo->nz)); 4819 coo->n = coo_n; 4820 coo->Atot = coo_n - nneg; // Annz is seqaij->nz, so no need to record that again 4821 coo->jmap = jmap; // of length nnz+1 4822 coo->perm = perm; 4823 PetscCall(PetscObjectContainerCompose((PetscObject)mat, "__PETSc_MatCOOStruct_Host", coo, MatCOOStructDestroy_SeqAIJ)); 4824 PetscFunctionReturn(PETSC_SUCCESS); 4825 } 4826 4827 static PetscErrorCode MatSetValuesCOO_SeqAIJ(Mat A, const PetscScalar v[], InsertMode imode) 4828 { 4829 Mat_SeqAIJ *aseq = (Mat_SeqAIJ *)A->data; 4830 PetscCount i, j, Annz = aseq->nz; 4831 PetscCount *perm, *jmap; 4832 PetscScalar *Aa; 4833 PetscContainer container; 4834 MatCOOStruct_SeqAIJ *coo; 4835 4836 PetscFunctionBegin; 4837 PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_MatCOOStruct_Host", (PetscObject *)&container)); 4838 PetscCheck(container, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not found MatCOOStruct on this matrix"); 4839 PetscCall(PetscContainerGetPointer(container, (void **)&coo)); 4840 perm = coo->perm; 4841 jmap = coo->jmap; 4842 PetscCall(MatSeqAIJGetArray(A, &Aa)); 4843 for (i = 0; i < Annz; i++) { 4844 PetscScalar sum = 0.0; 4845 for (j = jmap[i]; j < jmap[i + 1]; j++) sum += v[perm[j]]; 4846 Aa[i] = (imode == INSERT_VALUES ? 0.0 : Aa[i]) + sum; 4847 } 4848 PetscCall(MatSeqAIJRestoreArray(A, &Aa)); 4849 PetscFunctionReturn(PETSC_SUCCESS); 4850 } 4851 4852 #if defined(PETSC_HAVE_CUDA) 4853 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJCUSPARSE(Mat, MatType, MatReuse, Mat *); 4854 #endif 4855 #if defined(PETSC_HAVE_HIP) 4856 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJHIPSPARSE(Mat, MatType, MatReuse, Mat *); 4857 #endif 4858 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 4859 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJKokkos(Mat, MatType, MatReuse, Mat *); 4860 #endif 4861 4862 PETSC_EXTERN PetscErrorCode MatCreate_SeqAIJ(Mat B) 4863 { 4864 Mat_SeqAIJ *b; 4865 PetscMPIInt size; 4866 4867 PetscFunctionBegin; 4868 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)B), &size)); 4869 PetscCheck(size <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Comm must be of size 1"); 4870 4871 PetscCall(PetscNew(&b)); 4872 4873 B->data = (void *)b; 4874 B->ops[0] = MatOps_Values; 4875 if (B->sortedfull) B->ops->setvalues = MatSetValues_SeqAIJ_SortedFull; 4876 4877 b->row = NULL; 4878 b->col = NULL; 4879 b->icol = NULL; 4880 b->reallocs = 0; 4881 b->ignorezeroentries = PETSC_FALSE; 4882 b->roworiented = PETSC_TRUE; 4883 b->nonew = 0; 4884 b->diag = NULL; 4885 b->solve_work = NULL; 4886 B->spptr = NULL; 4887 b->saved_values = NULL; 4888 b->idiag = NULL; 4889 b->mdiag = NULL; 4890 b->ssor_work = NULL; 4891 b->omega = 1.0; 4892 b->fshift = 0.0; 4893 b->idiagvalid = PETSC_FALSE; 4894 b->ibdiagvalid = PETSC_FALSE; 4895 b->keepnonzeropattern = PETSC_FALSE; 4896 4897 PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATSEQAIJ)); 4898 #if defined(PETSC_HAVE_MATLAB) 4899 PetscCall(PetscObjectComposeFunction((PetscObject)B, "PetscMatlabEnginePut_C", MatlabEnginePut_SeqAIJ)); 4900 PetscCall(PetscObjectComposeFunction((PetscObject)B, "PetscMatlabEngineGet_C", MatlabEngineGet_SeqAIJ)); 4901 #endif 4902 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetColumnIndices_C", MatSeqAIJSetColumnIndices_SeqAIJ)); 4903 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatStoreValues_C", MatStoreValues_SeqAIJ)); 4904 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatRetrieveValues_C", MatRetrieveValues_SeqAIJ)); 4905 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqsbaij_C", MatConvert_SeqAIJ_SeqSBAIJ)); 4906 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqbaij_C", MatConvert_SeqAIJ_SeqBAIJ)); 4907 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijperm_C", MatConvert_SeqAIJ_SeqAIJPERM)); 4908 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijsell_C", MatConvert_SeqAIJ_SeqAIJSELL)); 4909 #if defined(PETSC_HAVE_MKL_SPARSE) 4910 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijmkl_C", MatConvert_SeqAIJ_SeqAIJMKL)); 4911 #endif 4912 #if defined(PETSC_HAVE_CUDA) 4913 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijcusparse_C", MatConvert_SeqAIJ_SeqAIJCUSPARSE)); 4914 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaijcusparse_seqaij_C", MatProductSetFromOptions_SeqAIJ)); 4915 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaijcusparse_C", MatProductSetFromOptions_SeqAIJ)); 4916 #endif 4917 #if defined(PETSC_HAVE_HIP) 4918 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijhipsparse_C", MatConvert_SeqAIJ_SeqAIJHIPSPARSE)); 4919 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaijhipsparse_seqaij_C", MatProductSetFromOptions_SeqAIJ)); 4920 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaijhipsparse_C", MatProductSetFromOptions_SeqAIJ)); 4921 #endif 4922 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 4923 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijkokkos_C", MatConvert_SeqAIJ_SeqAIJKokkos)); 4924 #endif 4925 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijcrl_C", MatConvert_SeqAIJ_SeqAIJCRL)); 4926 #if defined(PETSC_HAVE_ELEMENTAL) 4927 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_elemental_C", MatConvert_SeqAIJ_Elemental)); 4928 #endif 4929 #if defined(PETSC_HAVE_SCALAPACK) 4930 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_scalapack_C", MatConvert_AIJ_ScaLAPACK)); 4931 #endif 4932 #if defined(PETSC_HAVE_HYPRE) 4933 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_hypre_C", MatConvert_AIJ_HYPRE)); 4934 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_transpose_seqaij_seqaij_C", MatProductSetFromOptions_Transpose_AIJ_AIJ)); 4935 #endif 4936 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqdense_C", MatConvert_SeqAIJ_SeqDense)); 4937 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqsell_C", MatConvert_SeqAIJ_SeqSELL)); 4938 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_is_C", MatConvert_XAIJ_IS)); 4939 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsTranspose_C", MatIsTranspose_SeqAIJ)); 4940 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsHermitianTranspose_C", MatIsHermitianTranspose_SeqAIJ)); 4941 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetPreallocation_C", MatSeqAIJSetPreallocation_SeqAIJ)); 4942 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatResetPreallocation_C", MatResetPreallocation_SeqAIJ)); 4943 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatResetHash_C", MatResetHash_SeqAIJ)); 4944 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetPreallocationCSR_C", MatSeqAIJSetPreallocationCSR_SeqAIJ)); 4945 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatReorderForNonzeroDiagonal_C", MatReorderForNonzeroDiagonal_SeqAIJ)); 4946 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_is_seqaij_C", MatProductSetFromOptions_IS_XAIJ)); 4947 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqdense_seqaij_C", MatProductSetFromOptions_SeqDense_SeqAIJ)); 4948 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaij_C", MatProductSetFromOptions_SeqAIJ)); 4949 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJKron_C", MatSeqAIJKron_SeqAIJ)); 4950 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_SeqAIJ)); 4951 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSetValuesCOO_C", MatSetValuesCOO_SeqAIJ)); 4952 PetscCall(MatCreate_SeqAIJ_Inode(B)); 4953 PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATSEQAIJ)); 4954 PetscCall(MatSeqAIJSetTypeFromOptions(B)); /* this allows changing the matrix subtype to say MATSEQAIJPERM */ 4955 PetscFunctionReturn(PETSC_SUCCESS); 4956 } 4957 4958 /* 4959 Given a matrix generated with MatGetFactor() duplicates all the information in A into C 4960 */ 4961 PetscErrorCode MatDuplicateNoCreate_SeqAIJ(Mat C, Mat A, MatDuplicateOption cpvalues, PetscBool mallocmatspace) 4962 { 4963 Mat_SeqAIJ *c = (Mat_SeqAIJ *)C->data, *a = (Mat_SeqAIJ *)A->data; 4964 PetscInt m = A->rmap->n, i; 4965 4966 PetscFunctionBegin; 4967 PetscCheck(A->assembled || cpvalues == MAT_DO_NOT_COPY_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot duplicate unassembled matrix"); 4968 4969 C->factortype = A->factortype; 4970 c->row = NULL; 4971 c->col = NULL; 4972 c->icol = NULL; 4973 c->reallocs = 0; 4974 c->diagonaldense = a->diagonaldense; 4975 4976 C->assembled = A->assembled; 4977 4978 if (A->preallocated) { 4979 PetscCall(PetscLayoutReference(A->rmap, &C->rmap)); 4980 PetscCall(PetscLayoutReference(A->cmap, &C->cmap)); 4981 4982 if (!A->hash_active) { 4983 PetscCall(PetscMalloc1(m, &c->imax)); 4984 PetscCall(PetscMemcpy(c->imax, a->imax, m * sizeof(PetscInt))); 4985 PetscCall(PetscMalloc1(m, &c->ilen)); 4986 PetscCall(PetscMemcpy(c->ilen, a->ilen, m * sizeof(PetscInt))); 4987 4988 /* allocate the matrix space */ 4989 if (mallocmatspace) { 4990 PetscCall(PetscShmgetAllocateArray(a->i[m], sizeof(PetscScalar), (void **)&c->a)); 4991 PetscCall(PetscShmgetAllocateArray(a->i[m], sizeof(PetscInt), (void **)&c->j)); 4992 PetscCall(PetscShmgetAllocateArray(m + 1, sizeof(PetscInt), (void **)&c->i)); 4993 PetscCall(PetscArraycpy(c->i, a->i, m + 1)); 4994 c->free_a = PETSC_TRUE; 4995 c->free_ij = PETSC_TRUE; 4996 if (m > 0) { 4997 PetscCall(PetscArraycpy(c->j, a->j, a->i[m])); 4998 if (cpvalues == MAT_COPY_VALUES) { 4999 const PetscScalar *aa; 5000 5001 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 5002 PetscCall(PetscArraycpy(c->a, aa, a->i[m])); 5003 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 5004 } else { 5005 PetscCall(PetscArrayzero(c->a, a->i[m])); 5006 } 5007 } 5008 } 5009 C->preallocated = PETSC_TRUE; 5010 } else { 5011 PetscCheck(mallocmatspace, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Cannot malloc matrix memory from a non-preallocated matrix"); 5012 PetscCall(MatSetUp(C)); 5013 } 5014 5015 c->ignorezeroentries = a->ignorezeroentries; 5016 c->roworiented = a->roworiented; 5017 c->nonew = a->nonew; 5018 if (a->diag) { 5019 PetscCall(PetscMalloc1(m + 1, &c->diag)); 5020 PetscCall(PetscMemcpy(c->diag, a->diag, m * sizeof(PetscInt))); 5021 } else c->diag = NULL; 5022 5023 c->solve_work = NULL; 5024 c->saved_values = NULL; 5025 c->idiag = NULL; 5026 c->ssor_work = NULL; 5027 c->keepnonzeropattern = a->keepnonzeropattern; 5028 5029 c->rmax = a->rmax; 5030 c->nz = a->nz; 5031 c->maxnz = a->nz; /* Since we allocate exactly the right amount */ 5032 5033 c->compressedrow.use = a->compressedrow.use; 5034 c->compressedrow.nrows = a->compressedrow.nrows; 5035 if (a->compressedrow.use) { 5036 i = a->compressedrow.nrows; 5037 PetscCall(PetscMalloc2(i + 1, &c->compressedrow.i, i, &c->compressedrow.rindex)); 5038 PetscCall(PetscArraycpy(c->compressedrow.i, a->compressedrow.i, i + 1)); 5039 PetscCall(PetscArraycpy(c->compressedrow.rindex, a->compressedrow.rindex, i)); 5040 } else { 5041 c->compressedrow.use = PETSC_FALSE; 5042 c->compressedrow.i = NULL; 5043 c->compressedrow.rindex = NULL; 5044 } 5045 c->nonzerorowcnt = a->nonzerorowcnt; 5046 C->nonzerostate = A->nonzerostate; 5047 5048 PetscCall(MatDuplicate_SeqAIJ_Inode(A, cpvalues, &C)); 5049 } 5050 PetscCall(PetscFunctionListDuplicate(((PetscObject)A)->qlist, &((PetscObject)C)->qlist)); 5051 PetscFunctionReturn(PETSC_SUCCESS); 5052 } 5053 5054 PetscErrorCode MatDuplicate_SeqAIJ(Mat A, MatDuplicateOption cpvalues, Mat *B) 5055 { 5056 PetscFunctionBegin; 5057 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B)); 5058 PetscCall(MatSetSizes(*B, A->rmap->n, A->cmap->n, A->rmap->n, A->cmap->n)); 5059 if (!(A->rmap->n % A->rmap->bs) && !(A->cmap->n % A->cmap->bs)) PetscCall(MatSetBlockSizesFromMats(*B, A, A)); 5060 PetscCall(MatSetType(*B, ((PetscObject)A)->type_name)); 5061 PetscCall(MatDuplicateNoCreate_SeqAIJ(*B, A, cpvalues, PETSC_TRUE)); 5062 PetscFunctionReturn(PETSC_SUCCESS); 5063 } 5064 5065 PetscErrorCode MatLoad_SeqAIJ(Mat newMat, PetscViewer viewer) 5066 { 5067 PetscBool isbinary, ishdf5; 5068 5069 PetscFunctionBegin; 5070 PetscValidHeaderSpecific(newMat, MAT_CLASSID, 1); 5071 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 5072 /* force binary viewer to load .info file if it has not yet done so */ 5073 PetscCall(PetscViewerSetUp(viewer)); 5074 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 5075 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 5076 if (isbinary) { 5077 PetscCall(MatLoad_SeqAIJ_Binary(newMat, viewer)); 5078 } else if (ishdf5) { 5079 #if defined(PETSC_HAVE_HDF5) 5080 PetscCall(MatLoad_AIJ_HDF5(newMat, viewer)); 5081 #else 5082 SETERRQ(PetscObjectComm((PetscObject)newMat), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 5083 #endif 5084 } else { 5085 SETERRQ(PetscObjectComm((PetscObject)newMat), PETSC_ERR_SUP, "Viewer type %s not yet supported for reading %s matrices", ((PetscObject)viewer)->type_name, ((PetscObject)newMat)->type_name); 5086 } 5087 PetscFunctionReturn(PETSC_SUCCESS); 5088 } 5089 5090 PetscErrorCode MatLoad_SeqAIJ_Binary(Mat mat, PetscViewer viewer) 5091 { 5092 Mat_SeqAIJ *a = (Mat_SeqAIJ *)mat->data; 5093 PetscInt header[4], *rowlens, M, N, nz, sum, rows, cols, i; 5094 5095 PetscFunctionBegin; 5096 PetscCall(PetscViewerSetUp(viewer)); 5097 5098 /* read in matrix header */ 5099 PetscCall(PetscViewerBinaryRead(viewer, header, 4, NULL, PETSC_INT)); 5100 PetscCheck(header[0] == MAT_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a matrix object in file"); 5101 M = header[1]; 5102 N = header[2]; 5103 nz = header[3]; 5104 PetscCheck(M >= 0, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Matrix row size (%" PetscInt_FMT ") in file is negative", M); 5105 PetscCheck(N >= 0, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Matrix column size (%" PetscInt_FMT ") in file is negative", N); 5106 PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Matrix stored in special format on disk, cannot load as SeqAIJ"); 5107 5108 /* set block sizes from the viewer's .info file */ 5109 PetscCall(MatLoad_Binary_BlockSizes(mat, viewer)); 5110 /* set local and global sizes if not set already */ 5111 if (mat->rmap->n < 0) mat->rmap->n = M; 5112 if (mat->cmap->n < 0) mat->cmap->n = N; 5113 if (mat->rmap->N < 0) mat->rmap->N = M; 5114 if (mat->cmap->N < 0) mat->cmap->N = N; 5115 PetscCall(PetscLayoutSetUp(mat->rmap)); 5116 PetscCall(PetscLayoutSetUp(mat->cmap)); 5117 5118 /* check if the matrix sizes are correct */ 5119 PetscCall(MatGetSize(mat, &rows, &cols)); 5120 PetscCheck(M == rows && N == cols, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Matrix in file of different sizes (%" PetscInt_FMT ", %" PetscInt_FMT ") than the input matrix (%" PetscInt_FMT ", %" PetscInt_FMT ")", M, N, rows, cols); 5121 5122 /* read in row lengths */ 5123 PetscCall(PetscMalloc1(M, &rowlens)); 5124 PetscCall(PetscViewerBinaryRead(viewer, rowlens, M, NULL, PETSC_INT)); 5125 /* check if sum(rowlens) is same as nz */ 5126 sum = 0; 5127 for (i = 0; i < M; i++) sum += rowlens[i]; 5128 PetscCheck(sum == nz, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Inconsistent matrix data in file: nonzeros = %" PetscInt_FMT ", sum-row-lengths = %" PetscInt_FMT, nz, sum); 5129 /* preallocate and check sizes */ 5130 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(mat, 0, rowlens)); 5131 PetscCall(MatGetSize(mat, &rows, &cols)); 5132 PetscCheck(M == rows && N == cols, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Matrix in file of different length (%" PetscInt_FMT ", %" PetscInt_FMT ") than the input matrix (%" PetscInt_FMT ", %" PetscInt_FMT ")", M, N, rows, cols); 5133 /* store row lengths */ 5134 PetscCall(PetscArraycpy(a->ilen, rowlens, M)); 5135 PetscCall(PetscFree(rowlens)); 5136 5137 /* fill in "i" row pointers */ 5138 a->i[0] = 0; 5139 for (i = 0; i < M; i++) a->i[i + 1] = a->i[i] + a->ilen[i]; 5140 /* read in "j" column indices */ 5141 PetscCall(PetscViewerBinaryRead(viewer, a->j, nz, NULL, PETSC_INT)); 5142 /* read in "a" nonzero values */ 5143 PetscCall(PetscViewerBinaryRead(viewer, a->a, nz, NULL, PETSC_SCALAR)); 5144 5145 PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY)); 5146 PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY)); 5147 PetscFunctionReturn(PETSC_SUCCESS); 5148 } 5149 5150 PetscErrorCode MatEqual_SeqAIJ(Mat A, Mat B, PetscBool *flg) 5151 { 5152 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *b = (Mat_SeqAIJ *)B->data; 5153 const PetscScalar *aa, *ba; 5154 #if defined(PETSC_USE_COMPLEX) 5155 PetscInt k; 5156 #endif 5157 5158 PetscFunctionBegin; 5159 /* If the matrix dimensions are not equal,or no of nonzeros */ 5160 if ((A->rmap->n != B->rmap->n) || (A->cmap->n != B->cmap->n) || (a->nz != b->nz)) { 5161 *flg = PETSC_FALSE; 5162 PetscFunctionReturn(PETSC_SUCCESS); 5163 } 5164 5165 /* if the a->i are the same */ 5166 PetscCall(PetscArraycmp(a->i, b->i, A->rmap->n + 1, flg)); 5167 if (!*flg) PetscFunctionReturn(PETSC_SUCCESS); 5168 5169 /* if a->j are the same */ 5170 PetscCall(PetscArraycmp(a->j, b->j, a->nz, flg)); 5171 if (!*flg) PetscFunctionReturn(PETSC_SUCCESS); 5172 5173 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 5174 PetscCall(MatSeqAIJGetArrayRead(B, &ba)); 5175 /* if a->a are the same */ 5176 #if defined(PETSC_USE_COMPLEX) 5177 for (k = 0; k < a->nz; k++) { 5178 if (PetscRealPart(aa[k]) != PetscRealPart(ba[k]) || PetscImaginaryPart(aa[k]) != PetscImaginaryPart(ba[k])) { 5179 *flg = PETSC_FALSE; 5180 PetscFunctionReturn(PETSC_SUCCESS); 5181 } 5182 } 5183 #else 5184 PetscCall(PetscArraycmp(aa, ba, a->nz, flg)); 5185 #endif 5186 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 5187 PetscCall(MatSeqAIJRestoreArrayRead(B, &ba)); 5188 PetscFunctionReturn(PETSC_SUCCESS); 5189 } 5190 5191 /*@ 5192 MatCreateSeqAIJWithArrays - Creates an sequential `MATSEQAIJ` matrix using matrix elements (in CSR format) 5193 provided by the user. 5194 5195 Collective 5196 5197 Input Parameters: 5198 + comm - must be an MPI communicator of size 1 5199 . m - number of rows 5200 . n - number of columns 5201 . i - row indices; that is i[0] = 0, i[row] = i[row-1] + number of elements in that row of the matrix 5202 . j - column indices 5203 - a - matrix values 5204 5205 Output Parameter: 5206 . mat - the matrix 5207 5208 Level: intermediate 5209 5210 Notes: 5211 The `i`, `j`, and `a` arrays are not copied by this routine, the user must free these arrays 5212 once the matrix is destroyed and not before 5213 5214 You cannot set new nonzero locations into this matrix, that will generate an error. 5215 5216 The `i` and `j` indices are 0 based 5217 5218 The format which is used for the sparse matrix input, is equivalent to a 5219 row-major ordering.. i.e for the following matrix, the input data expected is 5220 as shown 5221 .vb 5222 1 0 0 5223 2 0 3 5224 4 5 6 5225 5226 i = {0,1,3,6} [size = nrow+1 = 3+1] 5227 j = {0,0,2,0,1,2} [size = 6]; values must be sorted for each row 5228 v = {1,2,3,4,5,6} [size = 6] 5229 .ve 5230 5231 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MatCreateMPIAIJWithArrays()`, `MatMPIAIJSetPreallocationCSR()` 5232 @*/ 5233 PetscErrorCode MatCreateSeqAIJWithArrays(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt i[], PetscInt j[], PetscScalar a[], Mat *mat) 5234 { 5235 PetscInt ii; 5236 Mat_SeqAIJ *aij; 5237 PetscInt jj; 5238 5239 PetscFunctionBegin; 5240 PetscCheck(m <= 0 || i[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "i (row indices) must start with 0"); 5241 PetscCall(MatCreate(comm, mat)); 5242 PetscCall(MatSetSizes(*mat, m, n, m, n)); 5243 /* PetscCall(MatSetBlockSizes(*mat,,)); */ 5244 PetscCall(MatSetType(*mat, MATSEQAIJ)); 5245 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*mat, MAT_SKIP_ALLOCATION, NULL)); 5246 aij = (Mat_SeqAIJ *)(*mat)->data; 5247 PetscCall(PetscMalloc1(m, &aij->imax)); 5248 PetscCall(PetscMalloc1(m, &aij->ilen)); 5249 5250 aij->i = i; 5251 aij->j = j; 5252 aij->a = a; 5253 aij->nonew = -1; /*this indicates that inserting a new value in the matrix that generates a new nonzero is an error*/ 5254 aij->free_a = PETSC_FALSE; 5255 aij->free_ij = PETSC_FALSE; 5256 5257 for (ii = 0, aij->nonzerorowcnt = 0, aij->rmax = 0; ii < m; ii++) { 5258 aij->ilen[ii] = aij->imax[ii] = i[ii + 1] - i[ii]; 5259 if (PetscDefined(USE_DEBUG)) { 5260 PetscCheck(i[ii + 1] - i[ii] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative row length in i (row indices) row = %" PetscInt_FMT " length = %" PetscInt_FMT, ii, i[ii + 1] - i[ii]); 5261 for (jj = i[ii] + 1; jj < i[ii + 1]; jj++) { 5262 PetscCheck(j[jj] >= j[jj - 1], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column entry number %" PetscInt_FMT " (actual column %" PetscInt_FMT ") in row %" PetscInt_FMT " is not sorted", jj - i[ii], j[jj], ii); 5263 PetscCheck(j[jj] != j[jj - 1], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column entry number %" PetscInt_FMT " (actual column %" PetscInt_FMT ") in row %" PetscInt_FMT " is identical to previous entry", jj - i[ii], j[jj], ii); 5264 } 5265 } 5266 } 5267 if (PetscDefined(USE_DEBUG)) { 5268 for (ii = 0; ii < aij->i[m]; ii++) { 5269 PetscCheck(j[ii] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative column index at location = %" PetscInt_FMT " index = %" PetscInt_FMT, ii, j[ii]); 5270 PetscCheck(j[ii] <= n - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column index to large at location = %" PetscInt_FMT " index = %" PetscInt_FMT " last column = %" PetscInt_FMT, ii, j[ii], n - 1); 5271 } 5272 } 5273 5274 PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY)); 5275 PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY)); 5276 PetscFunctionReturn(PETSC_SUCCESS); 5277 } 5278 5279 /*@ 5280 MatCreateSeqAIJFromTriple - Creates an sequential `MATSEQAIJ` matrix using matrix elements (in COO format) 5281 provided by the user. 5282 5283 Collective 5284 5285 Input Parameters: 5286 + comm - must be an MPI communicator of size 1 5287 . m - number of rows 5288 . n - number of columns 5289 . i - row indices 5290 . j - column indices 5291 . a - matrix values 5292 . nz - number of nonzeros 5293 - idx - if the `i` and `j` indices start with 1 use `PETSC_TRUE` otherwise use `PETSC_FALSE` 5294 5295 Output Parameter: 5296 . mat - the matrix 5297 5298 Level: intermediate 5299 5300 Example: 5301 For the following matrix, the input data expected is as shown (using 0 based indexing) 5302 .vb 5303 1 0 0 5304 2 0 3 5305 4 5 6 5306 5307 i = {0,1,1,2,2,2} 5308 j = {0,0,2,0,1,2} 5309 v = {1,2,3,4,5,6} 5310 .ve 5311 5312 Note: 5313 Instead of using this function, users should also consider `MatSetPreallocationCOO()` and `MatSetValuesCOO()`, which allow repeated or remote entries, 5314 and are particularly useful in iterative applications. 5315 5316 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MatCreateSeqAIJWithArrays()`, `MatMPIAIJSetPreallocationCSR()`, `MatSetValuesCOO()`, `MatSetPreallocationCOO()` 5317 @*/ 5318 PetscErrorCode MatCreateSeqAIJFromTriple(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt i[], PetscInt j[], PetscScalar a[], Mat *mat, PetscCount nz, PetscBool idx) 5319 { 5320 PetscInt ii, *nnz, one = 1, row, col; 5321 5322 PetscFunctionBegin; 5323 PetscCall(PetscCalloc1(m, &nnz)); 5324 for (ii = 0; ii < nz; ii++) nnz[i[ii] - !!idx] += 1; 5325 PetscCall(MatCreate(comm, mat)); 5326 PetscCall(MatSetSizes(*mat, m, n, m, n)); 5327 PetscCall(MatSetType(*mat, MATSEQAIJ)); 5328 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*mat, 0, nnz)); 5329 for (ii = 0; ii < nz; ii++) { 5330 if (idx) { 5331 row = i[ii] - 1; 5332 col = j[ii] - 1; 5333 } else { 5334 row = i[ii]; 5335 col = j[ii]; 5336 } 5337 PetscCall(MatSetValues(*mat, one, &row, one, &col, &a[ii], ADD_VALUES)); 5338 } 5339 PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY)); 5340 PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY)); 5341 PetscCall(PetscFree(nnz)); 5342 PetscFunctionReturn(PETSC_SUCCESS); 5343 } 5344 5345 PetscErrorCode MatSeqAIJInvalidateDiagonal(Mat A) 5346 { 5347 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 5348 5349 PetscFunctionBegin; 5350 a->idiagvalid = PETSC_FALSE; 5351 a->ibdiagvalid = PETSC_FALSE; 5352 5353 PetscCall(MatSeqAIJInvalidateDiagonal_Inode(A)); 5354 PetscFunctionReturn(PETSC_SUCCESS); 5355 } 5356 5357 PetscErrorCode MatCreateMPIMatConcatenateSeqMat_SeqAIJ(MPI_Comm comm, Mat inmat, PetscInt n, MatReuse scall, Mat *outmat) 5358 { 5359 PetscFunctionBegin; 5360 PetscCall(MatCreateMPIMatConcatenateSeqMat_MPIAIJ(comm, inmat, n, scall, outmat)); 5361 PetscFunctionReturn(PETSC_SUCCESS); 5362 } 5363 5364 /* 5365 Permute A into C's *local* index space using rowemb,colemb. 5366 The embedding are supposed to be injections and the above implies that the range of rowemb is a subset 5367 of [0,m), colemb is in [0,n). 5368 If pattern == DIFFERENT_NONZERO_PATTERN, C is preallocated according to A. 5369 */ 5370 PetscErrorCode MatSetSeqMat_SeqAIJ(Mat C, IS rowemb, IS colemb, MatStructure pattern, Mat B) 5371 { 5372 /* If making this function public, change the error returned in this function away from _PLIB. */ 5373 Mat_SeqAIJ *Baij; 5374 PetscBool seqaij; 5375 PetscInt m, n, *nz, i, j, count; 5376 PetscScalar v; 5377 const PetscInt *rowindices, *colindices; 5378 5379 PetscFunctionBegin; 5380 if (!B) PetscFunctionReturn(PETSC_SUCCESS); 5381 /* Check to make sure the target matrix (and embeddings) are compatible with C and each other. */ 5382 PetscCall(PetscObjectBaseTypeCompare((PetscObject)B, MATSEQAIJ, &seqaij)); 5383 PetscCheck(seqaij, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is of wrong type"); 5384 if (rowemb) { 5385 PetscCall(ISGetLocalSize(rowemb, &m)); 5386 PetscCheck(m == B->rmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Row IS of size %" PetscInt_FMT " is incompatible with matrix row size %" PetscInt_FMT, m, B->rmap->n); 5387 } else { 5388 PetscCheck(C->rmap->n == B->rmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is row-incompatible with the target matrix"); 5389 } 5390 if (colemb) { 5391 PetscCall(ISGetLocalSize(colemb, &n)); 5392 PetscCheck(n == B->cmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Diag col IS of size %" PetscInt_FMT " is incompatible with input matrix col size %" PetscInt_FMT, n, B->cmap->n); 5393 } else { 5394 PetscCheck(C->cmap->n == B->cmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is col-incompatible with the target matrix"); 5395 } 5396 5397 Baij = (Mat_SeqAIJ *)B->data; 5398 if (pattern == DIFFERENT_NONZERO_PATTERN) { 5399 PetscCall(PetscMalloc1(B->rmap->n, &nz)); 5400 for (i = 0; i < B->rmap->n; i++) nz[i] = Baij->i[i + 1] - Baij->i[i]; 5401 PetscCall(MatSeqAIJSetPreallocation(C, 0, nz)); 5402 PetscCall(PetscFree(nz)); 5403 } 5404 if (pattern == SUBSET_NONZERO_PATTERN) PetscCall(MatZeroEntries(C)); 5405 count = 0; 5406 rowindices = NULL; 5407 colindices = NULL; 5408 if (rowemb) PetscCall(ISGetIndices(rowemb, &rowindices)); 5409 if (colemb) PetscCall(ISGetIndices(colemb, &colindices)); 5410 for (i = 0; i < B->rmap->n; i++) { 5411 PetscInt row; 5412 row = i; 5413 if (rowindices) row = rowindices[i]; 5414 for (j = Baij->i[i]; j < Baij->i[i + 1]; j++) { 5415 PetscInt col; 5416 col = Baij->j[count]; 5417 if (colindices) col = colindices[col]; 5418 v = Baij->a[count]; 5419 PetscCall(MatSetValues(C, 1, &row, 1, &col, &v, INSERT_VALUES)); 5420 ++count; 5421 } 5422 } 5423 /* FIXME: set C's nonzerostate correctly. */ 5424 /* Assembly for C is necessary. */ 5425 C->preallocated = PETSC_TRUE; 5426 C->assembled = PETSC_TRUE; 5427 C->was_assembled = PETSC_FALSE; 5428 PetscFunctionReturn(PETSC_SUCCESS); 5429 } 5430 5431 PetscErrorCode MatEliminateZeros_SeqAIJ(Mat A, PetscBool keep) 5432 { 5433 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 5434 MatScalar *aa = a->a; 5435 PetscInt m = A->rmap->n, fshift = 0, fshift_prev = 0, i, k; 5436 PetscInt *ailen = a->ilen, *imax = a->imax, *ai = a->i, *aj = a->j, rmax = 0; 5437 5438 PetscFunctionBegin; 5439 PetscCheck(A->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot eliminate zeros for unassembled matrix"); 5440 if (m) rmax = ailen[0]; /* determine row with most nonzeros */ 5441 for (i = 1; i <= m; i++) { 5442 /* move each nonzero entry back by the amount of zero slots (fshift) before it*/ 5443 for (k = ai[i - 1]; k < ai[i]; k++) { 5444 if (aa[k] == 0 && (aj[k] != i - 1 || !keep)) fshift++; 5445 else { 5446 if (aa[k] == 0 && aj[k] == i - 1) PetscCall(PetscInfo(A, "Keep the diagonal zero at row %" PetscInt_FMT "\n", i - 1)); 5447 aa[k - fshift] = aa[k]; 5448 aj[k - fshift] = aj[k]; 5449 } 5450 } 5451 ai[i - 1] -= fshift_prev; // safe to update ai[i-1] now since it will not be used in the next iteration 5452 fshift_prev = fshift; 5453 /* reset ilen and imax for each row */ 5454 ailen[i - 1] = imax[i - 1] = ai[i] - fshift - ai[i - 1]; 5455 a->nonzerorowcnt += ((ai[i] - fshift - ai[i - 1]) > 0); 5456 rmax = PetscMax(rmax, ailen[i - 1]); 5457 } 5458 if (fshift) { 5459 if (m) { 5460 ai[m] -= fshift; 5461 a->nz = ai[m]; 5462 } 5463 PetscCall(PetscInfo(A, "Matrix size: %" PetscInt_FMT " X %" PetscInt_FMT "; zeros eliminated: %" PetscInt_FMT "; nonzeros left: %" PetscInt_FMT "\n", m, A->cmap->n, fshift, a->nz)); 5464 A->nonzerostate++; 5465 A->info.nz_unneeded += (PetscReal)fshift; 5466 a->rmax = rmax; 5467 if (a->inode.use && a->inode.checked) PetscCall(MatSeqAIJCheckInode(A)); 5468 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 5469 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 5470 } 5471 PetscFunctionReturn(PETSC_SUCCESS); 5472 } 5473 5474 PetscFunctionList MatSeqAIJList = NULL; 5475 5476 /*@ 5477 MatSeqAIJSetType - Converts a `MATSEQAIJ` matrix to a subtype 5478 5479 Collective 5480 5481 Input Parameters: 5482 + mat - the matrix object 5483 - matype - matrix type 5484 5485 Options Database Key: 5486 . -mat_seqaij_type <method> - for example seqaijcrl 5487 5488 Level: intermediate 5489 5490 .seealso: [](ch_matrices), `Mat`, `PCSetType()`, `VecSetType()`, `MatCreate()`, `MatType` 5491 @*/ 5492 PetscErrorCode MatSeqAIJSetType(Mat mat, MatType matype) 5493 { 5494 PetscBool sametype; 5495 PetscErrorCode (*r)(Mat, MatType, MatReuse, Mat *); 5496 5497 PetscFunctionBegin; 5498 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 5499 PetscCall(PetscObjectTypeCompare((PetscObject)mat, matype, &sametype)); 5500 if (sametype) PetscFunctionReturn(PETSC_SUCCESS); 5501 5502 PetscCall(PetscFunctionListFind(MatSeqAIJList, matype, &r)); 5503 PetscCheck(r, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown Mat type given: %s", matype); 5504 PetscCall((*r)(mat, matype, MAT_INPLACE_MATRIX, &mat)); 5505 PetscFunctionReturn(PETSC_SUCCESS); 5506 } 5507 5508 /*@C 5509 MatSeqAIJRegister - - Adds a new sub-matrix type for sequential `MATSEQAIJ` matrices 5510 5511 Not Collective, No Fortran Support 5512 5513 Input Parameters: 5514 + sname - name of a new user-defined matrix type, for example `MATSEQAIJCRL` 5515 - function - routine to convert to subtype 5516 5517 Level: advanced 5518 5519 Notes: 5520 `MatSeqAIJRegister()` may be called multiple times to add several user-defined solvers. 5521 5522 Then, your matrix can be chosen with the procedural interface at runtime via the option 5523 .vb 5524 -mat_seqaij_type my_mat 5525 .ve 5526 5527 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJRegisterAll()` 5528 @*/ 5529 PetscErrorCode MatSeqAIJRegister(const char sname[], PetscErrorCode (*function)(Mat, MatType, MatReuse, Mat *)) 5530 { 5531 PetscFunctionBegin; 5532 PetscCall(MatInitializePackage()); 5533 PetscCall(PetscFunctionListAdd(&MatSeqAIJList, sname, function)); 5534 PetscFunctionReturn(PETSC_SUCCESS); 5535 } 5536 5537 PetscBool MatSeqAIJRegisterAllCalled = PETSC_FALSE; 5538 5539 /*@C 5540 MatSeqAIJRegisterAll - Registers all of the matrix subtypes of `MATSSEQAIJ` 5541 5542 Not Collective 5543 5544 Level: advanced 5545 5546 Note: 5547 This registers the versions of `MATSEQAIJ` for GPUs 5548 5549 .seealso: [](ch_matrices), `Mat`, `MatRegisterAll()`, `MatSeqAIJRegister()` 5550 @*/ 5551 PetscErrorCode MatSeqAIJRegisterAll(void) 5552 { 5553 PetscFunctionBegin; 5554 if (MatSeqAIJRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS); 5555 MatSeqAIJRegisterAllCalled = PETSC_TRUE; 5556 5557 PetscCall(MatSeqAIJRegister(MATSEQAIJCRL, MatConvert_SeqAIJ_SeqAIJCRL)); 5558 PetscCall(MatSeqAIJRegister(MATSEQAIJPERM, MatConvert_SeqAIJ_SeqAIJPERM)); 5559 PetscCall(MatSeqAIJRegister(MATSEQAIJSELL, MatConvert_SeqAIJ_SeqAIJSELL)); 5560 #if defined(PETSC_HAVE_MKL_SPARSE) 5561 PetscCall(MatSeqAIJRegister(MATSEQAIJMKL, MatConvert_SeqAIJ_SeqAIJMKL)); 5562 #endif 5563 #if defined(PETSC_HAVE_CUDA) 5564 PetscCall(MatSeqAIJRegister(MATSEQAIJCUSPARSE, MatConvert_SeqAIJ_SeqAIJCUSPARSE)); 5565 #endif 5566 #if defined(PETSC_HAVE_HIP) 5567 PetscCall(MatSeqAIJRegister(MATSEQAIJHIPSPARSE, MatConvert_SeqAIJ_SeqAIJHIPSPARSE)); 5568 #endif 5569 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 5570 PetscCall(MatSeqAIJRegister(MATSEQAIJKOKKOS, MatConvert_SeqAIJ_SeqAIJKokkos)); 5571 #endif 5572 #if defined(PETSC_HAVE_VIENNACL) && defined(PETSC_HAVE_VIENNACL_NO_CUDA) 5573 PetscCall(MatSeqAIJRegister(MATMPIAIJVIENNACL, MatConvert_SeqAIJ_SeqAIJViennaCL)); 5574 #endif 5575 PetscFunctionReturn(PETSC_SUCCESS); 5576 } 5577 5578 /* 5579 Special version for direct calls from Fortran 5580 */ 5581 #if defined(PETSC_HAVE_FORTRAN_CAPS) 5582 #define matsetvaluesseqaij_ MATSETVALUESSEQAIJ 5583 #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE) 5584 #define matsetvaluesseqaij_ matsetvaluesseqaij 5585 #endif 5586 5587 /* Change these macros so can be used in void function */ 5588 5589 /* Change these macros so can be used in void function */ 5590 /* Identical to PetscCallVoid, except it assigns to *_ierr */ 5591 #undef PetscCall 5592 #define PetscCall(...) \ 5593 do { \ 5594 PetscErrorCode ierr_msv_mpiaij = __VA_ARGS__; \ 5595 if (PetscUnlikely(ierr_msv_mpiaij)) { \ 5596 *_ierr = PetscError(PETSC_COMM_SELF, __LINE__, PETSC_FUNCTION_NAME, __FILE__, ierr_msv_mpiaij, PETSC_ERROR_REPEAT, " "); \ 5597 return; \ 5598 } \ 5599 } while (0) 5600 5601 #undef SETERRQ 5602 #define SETERRQ(comm, ierr, ...) \ 5603 do { \ 5604 *_ierr = PetscError(comm, __LINE__, PETSC_FUNCTION_NAME, __FILE__, ierr, PETSC_ERROR_INITIAL, __VA_ARGS__); \ 5605 return; \ 5606 } while (0) 5607 5608 PETSC_EXTERN void matsetvaluesseqaij_(Mat *AA, PetscInt *mm, const PetscInt im[], PetscInt *nn, const PetscInt in[], const PetscScalar v[], InsertMode *isis, PetscErrorCode *_ierr) 5609 { 5610 Mat A = *AA; 5611 PetscInt m = *mm, n = *nn; 5612 InsertMode is = *isis; 5613 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 5614 PetscInt *rp, k, low, high, t, ii, row, nrow, i, col, l, rmax, N; 5615 PetscInt *imax, *ai, *ailen; 5616 PetscInt *aj, nonew = a->nonew, lastcol = -1; 5617 MatScalar *ap, value, *aa; 5618 PetscBool ignorezeroentries = a->ignorezeroentries; 5619 PetscBool roworiented = a->roworiented; 5620 5621 PetscFunctionBegin; 5622 MatCheckPreallocated(A, 1); 5623 imax = a->imax; 5624 ai = a->i; 5625 ailen = a->ilen; 5626 aj = a->j; 5627 aa = a->a; 5628 5629 for (k = 0; k < m; k++) { /* loop over added rows */ 5630 row = im[k]; 5631 if (row < 0) continue; 5632 PetscCheck(row < A->rmap->n, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large"); 5633 rp = aj + ai[row]; 5634 ap = aa + ai[row]; 5635 rmax = imax[row]; 5636 nrow = ailen[row]; 5637 low = 0; 5638 high = nrow; 5639 for (l = 0; l < n; l++) { /* loop over added columns */ 5640 if (in[l] < 0) continue; 5641 PetscCheck(in[l] < A->cmap->n, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Column too large"); 5642 col = in[l]; 5643 if (roworiented) value = v[l + k * n]; 5644 else value = v[k + l * m]; 5645 5646 if (value == 0.0 && ignorezeroentries && (is == ADD_VALUES)) continue; 5647 5648 if (col <= lastcol) low = 0; 5649 else high = nrow; 5650 lastcol = col; 5651 while (high - low > 5) { 5652 t = (low + high) / 2; 5653 if (rp[t] > col) high = t; 5654 else low = t; 5655 } 5656 for (i = low; i < high; i++) { 5657 if (rp[i] > col) break; 5658 if (rp[i] == col) { 5659 if (is == ADD_VALUES) ap[i] += value; 5660 else ap[i] = value; 5661 goto noinsert; 5662 } 5663 } 5664 if (value == 0.0 && ignorezeroentries) goto noinsert; 5665 if (nonew == 1) goto noinsert; 5666 PetscCheck(nonew != -1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero in the matrix"); 5667 MatSeqXAIJReallocateAIJ(A, A->rmap->n, 1, nrow, row, col, rmax, aa, ai, aj, rp, ap, imax, nonew, MatScalar); 5668 N = nrow++ - 1; 5669 a->nz++; 5670 high++; 5671 /* shift up all the later entries in this row */ 5672 for (ii = N; ii >= i; ii--) { 5673 rp[ii + 1] = rp[ii]; 5674 ap[ii + 1] = ap[ii]; 5675 } 5676 rp[i] = col; 5677 ap[i] = value; 5678 noinsert:; 5679 low = i + 1; 5680 } 5681 ailen[row] = nrow; 5682 } 5683 PetscFunctionReturnVoid(); 5684 } 5685 /* Undefining these here since they were redefined from their original definition above! No 5686 * other PETSc functions should be defined past this point, as it is impossible to recover the 5687 * original definitions */ 5688 #undef PetscCall 5689 #undef SETERRQ 5690