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