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