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