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