1 /* 2 Defines the basic matrix operations for the AIJ (compressed row) 3 matrix storage format. 4 */ 5 6 #include <../src/mat/impls/aij/seq/aij.h> /*I "petscmat.h" I*/ 7 #include <petscblaslapack.h> 8 #include <petscbt.h> 9 #include <petsc/private/kernels/blocktranspose.h> 10 11 /* defines MatSetValues_Seq_Hash(), MatAssemblyEnd_Seq_Hash(), MatSetUp_Seq_Hash() */ 12 #define TYPE AIJ 13 #define TYPE_BS 14 #include "../src/mat/impls/aij/seq/seqhashmatsetvalues.h" 15 #include "../src/mat/impls/aij/seq/seqhashmat.h" 16 #undef TYPE 17 #undef TYPE_BS 18 19 static PetscErrorCode MatSeqAIJSetTypeFromOptions(Mat A) 20 { 21 PetscBool flg; 22 char type[256]; 23 24 PetscFunctionBegin; 25 PetscObjectOptionsBegin((PetscObject)A); 26 PetscCall(PetscOptionsFList("-mat_seqaij_type", "Matrix SeqAIJ type", "MatSeqAIJSetType", MatSeqAIJList, "seqaij", type, 256, &flg)); 27 if (flg) PetscCall(MatSeqAIJSetType(A, type)); 28 PetscOptionsEnd(); 29 PetscFunctionReturn(PETSC_SUCCESS); 30 } 31 32 static PetscErrorCode MatGetColumnReductions_SeqAIJ(Mat A, PetscInt type, PetscReal *reductions) 33 { 34 PetscInt i, m, n; 35 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 36 37 PetscFunctionBegin; 38 PetscCall(MatGetSize(A, &m, &n)); 39 PetscCall(PetscArrayzero(reductions, n)); 40 if (type == NORM_2) { 41 for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] += PetscAbsScalar(aij->a[i] * aij->a[i]); 42 } else if (type == NORM_1) { 43 for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] += PetscAbsScalar(aij->a[i]); 44 } else if (type == NORM_INFINITY) { 45 for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] = PetscMax(PetscAbsScalar(aij->a[i]), reductions[aij->j[i]]); 46 } else if (type == REDUCTION_SUM_REALPART || type == REDUCTION_MEAN_REALPART) { 47 for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] += PetscRealPart(aij->a[i]); 48 } else if (type == REDUCTION_SUM_IMAGINARYPART || type == REDUCTION_MEAN_IMAGINARYPART) { 49 for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] += PetscImaginaryPart(aij->a[i]); 50 } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Unknown reduction type"); 51 52 if (type == NORM_2) { 53 for (i = 0; i < n; i++) reductions[i] = PetscSqrtReal(reductions[i]); 54 } else if (type == REDUCTION_MEAN_REALPART || type == REDUCTION_MEAN_IMAGINARYPART) { 55 for (i = 0; i < n; i++) reductions[i] /= m; 56 } 57 PetscFunctionReturn(PETSC_SUCCESS); 58 } 59 60 static PetscErrorCode MatFindOffBlockDiagonalEntries_SeqAIJ(Mat A, IS *is) 61 { 62 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 63 PetscInt i, m = A->rmap->n, cnt = 0, bs = A->rmap->bs; 64 const PetscInt *jj = a->j, *ii = a->i; 65 PetscInt *rows; 66 67 PetscFunctionBegin; 68 for (i = 0; i < m; i++) { 69 if ((ii[i] != ii[i + 1]) && ((jj[ii[i]] < bs * (i / bs)) || (jj[ii[i + 1] - 1] > bs * ((i + bs) / bs) - 1))) cnt++; 70 } 71 PetscCall(PetscMalloc1(cnt, &rows)); 72 cnt = 0; 73 for (i = 0; i < m; i++) { 74 if ((ii[i] != ii[i + 1]) && ((jj[ii[i]] < bs * (i / bs)) || (jj[ii[i + 1] - 1] > bs * ((i + bs) / bs) - 1))) { 75 rows[cnt] = i; 76 cnt++; 77 } 78 } 79 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cnt, rows, PETSC_OWN_POINTER, is)); 80 PetscFunctionReturn(PETSC_SUCCESS); 81 } 82 83 PetscErrorCode MatFindZeroDiagonals_SeqAIJ_Private(Mat A, PetscInt *nrows, PetscInt **zrows) 84 { 85 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 86 const MatScalar *aa; 87 PetscInt i, m = A->rmap->n, cnt = 0; 88 const PetscInt *ii = a->i, *jj = a->j, *diag; 89 PetscInt *rows; 90 91 PetscFunctionBegin; 92 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 93 PetscCall(MatMarkDiagonal_SeqAIJ(A)); 94 diag = a->diag; 95 for (i = 0; i < m; i++) { 96 if ((diag[i] >= ii[i + 1]) || (jj[diag[i]] != i) || (aa[diag[i]] == 0.0)) cnt++; 97 } 98 PetscCall(PetscMalloc1(cnt, &rows)); 99 cnt = 0; 100 for (i = 0; i < m; i++) { 101 if ((diag[i] >= ii[i + 1]) || (jj[diag[i]] != i) || (aa[diag[i]] == 0.0)) rows[cnt++] = i; 102 } 103 *nrows = cnt; 104 *zrows = rows; 105 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 106 PetscFunctionReturn(PETSC_SUCCESS); 107 } 108 109 static PetscErrorCode MatFindZeroDiagonals_SeqAIJ(Mat A, IS *zrows) 110 { 111 PetscInt nrows, *rows; 112 113 PetscFunctionBegin; 114 *zrows = NULL; 115 PetscCall(MatFindZeroDiagonals_SeqAIJ_Private(A, &nrows, &rows)); 116 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), nrows, rows, PETSC_OWN_POINTER, zrows)); 117 PetscFunctionReturn(PETSC_SUCCESS); 118 } 119 120 static PetscErrorCode MatFindNonzeroRows_SeqAIJ(Mat A, IS *keptrows) 121 { 122 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 123 const MatScalar *aa; 124 PetscInt m = A->rmap->n, cnt = 0; 125 const PetscInt *ii; 126 PetscInt n, i, j, *rows; 127 128 PetscFunctionBegin; 129 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 130 *keptrows = NULL; 131 ii = a->i; 132 for (i = 0; i < m; i++) { 133 n = ii[i + 1] - ii[i]; 134 if (!n) { 135 cnt++; 136 goto ok1; 137 } 138 for (j = ii[i]; j < ii[i + 1]; j++) { 139 if (aa[j] != 0.0) goto ok1; 140 } 141 cnt++; 142 ok1:; 143 } 144 if (!cnt) { 145 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 146 PetscFunctionReturn(PETSC_SUCCESS); 147 } 148 PetscCall(PetscMalloc1(A->rmap->n - cnt, &rows)); 149 cnt = 0; 150 for (i = 0; i < m; i++) { 151 n = ii[i + 1] - ii[i]; 152 if (!n) continue; 153 for (j = ii[i]; j < ii[i + 1]; j++) { 154 if (aa[j] != 0.0) { 155 rows[cnt++] = i; 156 break; 157 } 158 } 159 } 160 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 161 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cnt, rows, PETSC_OWN_POINTER, keptrows)); 162 PetscFunctionReturn(PETSC_SUCCESS); 163 } 164 165 PetscErrorCode MatDiagonalSet_SeqAIJ(Mat Y, Vec D, InsertMode is) 166 { 167 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)Y->data; 168 PetscInt i, m = Y->rmap->n; 169 const PetscInt *diag; 170 MatScalar *aa; 171 const PetscScalar *v; 172 PetscBool missing; 173 174 PetscFunctionBegin; 175 if (Y->assembled) { 176 PetscCall(MatMissingDiagonal_SeqAIJ(Y, &missing, NULL)); 177 if (!missing) { 178 diag = aij->diag; 179 PetscCall(VecGetArrayRead(D, &v)); 180 PetscCall(MatSeqAIJGetArray(Y, &aa)); 181 if (is == INSERT_VALUES) { 182 for (i = 0; i < m; i++) aa[diag[i]] = v[i]; 183 } else { 184 for (i = 0; i < m; i++) aa[diag[i]] += v[i]; 185 } 186 PetscCall(MatSeqAIJRestoreArray(Y, &aa)); 187 PetscCall(VecRestoreArrayRead(D, &v)); 188 PetscFunctionReturn(PETSC_SUCCESS); 189 } 190 PetscCall(MatSeqAIJInvalidateDiagonal(Y)); 191 } 192 PetscCall(MatDiagonalSet_Default(Y, D, is)); 193 PetscFunctionReturn(PETSC_SUCCESS); 194 } 195 196 PetscErrorCode MatGetRowIJ_SeqAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *m, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done) 197 { 198 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 199 PetscInt i, ishift; 200 201 PetscFunctionBegin; 202 if (m) *m = A->rmap->n; 203 if (!ia) PetscFunctionReturn(PETSC_SUCCESS); 204 ishift = 0; 205 if (symmetric && A->structurally_symmetric != PETSC_BOOL3_TRUE) { 206 PetscCall(MatToSymmetricIJ_SeqAIJ(A->rmap->n, a->i, a->j, PETSC_TRUE, ishift, oshift, (PetscInt **)ia, (PetscInt **)ja)); 207 } else if (oshift == 1) { 208 PetscInt *tia; 209 PetscInt nz = a->i[A->rmap->n]; 210 /* malloc space and add 1 to i and j indices */ 211 PetscCall(PetscMalloc1(A->rmap->n + 1, &tia)); 212 for (i = 0; i < A->rmap->n + 1; i++) tia[i] = a->i[i] + 1; 213 *ia = tia; 214 if (ja) { 215 PetscInt *tja; 216 PetscCall(PetscMalloc1(nz + 1, &tja)); 217 for (i = 0; i < nz; i++) tja[i] = a->j[i] + 1; 218 *ja = tja; 219 } 220 } else { 221 *ia = a->i; 222 if (ja) *ja = a->j; 223 } 224 PetscFunctionReturn(PETSC_SUCCESS); 225 } 226 227 PetscErrorCode MatRestoreRowIJ_SeqAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done) 228 { 229 PetscFunctionBegin; 230 if (!ia) PetscFunctionReturn(PETSC_SUCCESS); 231 if ((symmetric && A->structurally_symmetric != PETSC_BOOL3_TRUE) || oshift == 1) { 232 PetscCall(PetscFree(*ia)); 233 if (ja) PetscCall(PetscFree(*ja)); 234 } 235 PetscFunctionReturn(PETSC_SUCCESS); 236 } 237 238 PetscErrorCode MatGetColumnIJ_SeqAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *nn, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done) 239 { 240 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 241 PetscInt i, *collengths, *cia, *cja, n = A->cmap->n, m = A->rmap->n; 242 PetscInt nz = a->i[m], row, *jj, mr, col; 243 244 PetscFunctionBegin; 245 *nn = n; 246 if (!ia) PetscFunctionReturn(PETSC_SUCCESS); 247 if (symmetric) { 248 PetscCall(MatToSymmetricIJ_SeqAIJ(A->rmap->n, a->i, a->j, PETSC_TRUE, 0, oshift, (PetscInt **)ia, (PetscInt **)ja)); 249 } else { 250 PetscCall(PetscCalloc1(n, &collengths)); 251 PetscCall(PetscMalloc1(n + 1, &cia)); 252 PetscCall(PetscMalloc1(nz, &cja)); 253 jj = a->j; 254 for (i = 0; i < nz; i++) collengths[jj[i]]++; 255 cia[0] = oshift; 256 for (i = 0; i < n; i++) cia[i + 1] = cia[i] + collengths[i]; 257 PetscCall(PetscArrayzero(collengths, n)); 258 jj = a->j; 259 for (row = 0; row < m; row++) { 260 mr = a->i[row + 1] - a->i[row]; 261 for (i = 0; i < mr; i++) { 262 col = *jj++; 263 264 cja[cia[col] + collengths[col]++ - oshift] = row + oshift; 265 } 266 } 267 PetscCall(PetscFree(collengths)); 268 *ia = cia; 269 *ja = cja; 270 } 271 PetscFunctionReturn(PETSC_SUCCESS); 272 } 273 274 PetscErrorCode MatRestoreColumnIJ_SeqAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done) 275 { 276 PetscFunctionBegin; 277 if (!ia) PetscFunctionReturn(PETSC_SUCCESS); 278 279 PetscCall(PetscFree(*ia)); 280 PetscCall(PetscFree(*ja)); 281 PetscFunctionReturn(PETSC_SUCCESS); 282 } 283 284 /* 285 MatGetColumnIJ_SeqAIJ_Color() and MatRestoreColumnIJ_SeqAIJ_Color() are customized from 286 MatGetColumnIJ_SeqAIJ() and MatRestoreColumnIJ_SeqAIJ() by adding an output 287 spidx[], index of a->a, to be used in MatTransposeColoringCreate_SeqAIJ() and MatFDColoringCreate_SeqXAIJ() 288 */ 289 PetscErrorCode MatGetColumnIJ_SeqAIJ_Color(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *nn, const PetscInt *ia[], const PetscInt *ja[], PetscInt *spidx[], PetscBool *done) 290 { 291 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 292 PetscInt i, *collengths, *cia, *cja, n = A->cmap->n, m = A->rmap->n; 293 PetscInt nz = a->i[m], row, mr, col, tmp; 294 PetscInt *cspidx; 295 const PetscInt *jj; 296 297 PetscFunctionBegin; 298 *nn = n; 299 if (!ia) PetscFunctionReturn(PETSC_SUCCESS); 300 301 PetscCall(PetscCalloc1(n, &collengths)); 302 PetscCall(PetscMalloc1(n + 1, &cia)); 303 PetscCall(PetscMalloc1(nz, &cja)); 304 PetscCall(PetscMalloc1(nz, &cspidx)); 305 jj = a->j; 306 for (i = 0; i < nz; i++) collengths[jj[i]]++; 307 cia[0] = oshift; 308 for (i = 0; i < n; i++) cia[i + 1] = cia[i] + collengths[i]; 309 PetscCall(PetscArrayzero(collengths, n)); 310 jj = a->j; 311 for (row = 0; row < m; row++) { 312 mr = a->i[row + 1] - a->i[row]; 313 for (i = 0; i < mr; i++) { 314 col = *jj++; 315 tmp = cia[col] + collengths[col]++ - oshift; 316 cspidx[tmp] = a->i[row] + i; /* index of a->j */ 317 cja[tmp] = row + oshift; 318 } 319 } 320 PetscCall(PetscFree(collengths)); 321 *ia = cia; 322 *ja = cja; 323 *spidx = cspidx; 324 PetscFunctionReturn(PETSC_SUCCESS); 325 } 326 327 PetscErrorCode MatRestoreColumnIJ_SeqAIJ_Color(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscInt *spidx[], PetscBool *done) 328 { 329 PetscFunctionBegin; 330 PetscCall(MatRestoreColumnIJ_SeqAIJ(A, oshift, symmetric, inodecompressed, n, ia, ja, done)); 331 PetscCall(PetscFree(*spidx)); 332 PetscFunctionReturn(PETSC_SUCCESS); 333 } 334 335 static PetscErrorCode MatSetValuesRow_SeqAIJ(Mat A, PetscInt row, const PetscScalar v[]) 336 { 337 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 338 PetscInt *ai = a->i; 339 PetscScalar *aa; 340 341 PetscFunctionBegin; 342 PetscCall(MatSeqAIJGetArray(A, &aa)); 343 PetscCall(PetscArraycpy(aa + ai[row], v, ai[row + 1] - ai[row])); 344 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 345 PetscFunctionReturn(PETSC_SUCCESS); 346 } 347 348 /* 349 MatSeqAIJSetValuesLocalFast - An optimized version of MatSetValuesLocal() for SeqAIJ matrices with several assumptions 350 351 - a single row of values is set with each call 352 - no row or column indices are negative or (in error) larger than the number of rows or columns 353 - the values are always added to the matrix, not set 354 - no new locations are introduced in the nonzero structure of the matrix 355 356 This does NOT assume the global column indices are sorted 357 358 */ 359 360 #include <petsc/private/isimpl.h> 361 PetscErrorCode MatSeqAIJSetValuesLocalFast(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is) 362 { 363 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 364 PetscInt low, high, t, row, nrow, i, col, l; 365 const PetscInt *rp, *ai = a->i, *ailen = a->ilen, *aj = a->j; 366 PetscInt lastcol = -1; 367 MatScalar *ap, value, *aa; 368 const PetscInt *ridx = A->rmap->mapping->indices, *cidx = A->cmap->mapping->indices; 369 370 PetscFunctionBegin; 371 PetscCall(MatSeqAIJGetArray(A, &aa)); 372 row = ridx[im[0]]; 373 rp = aj + ai[row]; 374 ap = aa + ai[row]; 375 nrow = ailen[row]; 376 low = 0; 377 high = nrow; 378 for (l = 0; l < n; l++) { /* loop over added columns */ 379 col = cidx[in[l]]; 380 value = v[l]; 381 382 if (col <= lastcol) low = 0; 383 else high = nrow; 384 lastcol = col; 385 while (high - low > 5) { 386 t = (low + high) / 2; 387 if (rp[t] > col) high = t; 388 else low = t; 389 } 390 for (i = low; i < high; i++) { 391 if (rp[i] == col) { 392 ap[i] += value; 393 low = i + 1; 394 break; 395 } 396 } 397 } 398 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 399 return PETSC_SUCCESS; 400 } 401 402 PetscErrorCode MatSetValues_SeqAIJ(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is) 403 { 404 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 405 PetscInt *rp, k, low, high, t, ii, row, nrow, i, col, l, rmax, N; 406 PetscInt *imax = a->imax, *ai = a->i, *ailen = a->ilen; 407 PetscInt *aj = a->j, nonew = a->nonew, lastcol = -1; 408 MatScalar *ap = NULL, value = 0.0, *aa; 409 PetscBool ignorezeroentries = a->ignorezeroentries; 410 PetscBool roworiented = a->roworiented; 411 412 PetscFunctionBegin; 413 PetscCall(MatSeqAIJGetArray(A, &aa)); 414 for (k = 0; k < m; k++) { /* loop over added rows */ 415 row = im[k]; 416 if (row < 0) continue; 417 PetscCheck(row < A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, row, A->rmap->n - 1); 418 rp = PetscSafePointerPlusOffset(aj, ai[row]); 419 if (!A->structure_only) ap = PetscSafePointerPlusOffset(aa, ai[row]); 420 rmax = imax[row]; 421 nrow = ailen[row]; 422 low = 0; 423 high = nrow; 424 for (l = 0; l < n; l++) { /* loop over added columns */ 425 if (in[l] < 0) continue; 426 PetscCheck(in[l] < A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column too large: col %" PetscInt_FMT " max %" PetscInt_FMT, in[l], A->cmap->n - 1); 427 col = in[l]; 428 if (v && !A->structure_only) value = roworiented ? v[l + k * n] : v[k + l * m]; 429 if (!A->structure_only && value == 0.0 && ignorezeroentries && is == ADD_VALUES && row != col) continue; 430 431 if (col <= lastcol) low = 0; 432 else high = nrow; 433 lastcol = col; 434 while (high - low > 5) { 435 t = (low + high) / 2; 436 if (rp[t] > col) high = t; 437 else low = t; 438 } 439 for (i = low; i < high; i++) { 440 if (rp[i] > col) break; 441 if (rp[i] == col) { 442 if (!A->structure_only) { 443 if (is == ADD_VALUES) { 444 ap[i] += value; 445 (void)PetscLogFlops(1.0); 446 } else ap[i] = value; 447 } 448 low = i + 1; 449 goto noinsert; 450 } 451 } 452 if (value == 0.0 && ignorezeroentries && row != col) goto noinsert; 453 if (nonew == 1) goto noinsert; 454 PetscCheck(nonew != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero at (%" PetscInt_FMT ",%" PetscInt_FMT ") in the matrix", row, col); 455 if (A->structure_only) { 456 MatSeqXAIJReallocateAIJ_structure_only(A, A->rmap->n, 1, nrow, row, col, rmax, ai, aj, rp, imax, nonew, MatScalar); 457 } else { 458 MatSeqXAIJReallocateAIJ(A, A->rmap->n, 1, nrow, row, col, rmax, aa, ai, aj, rp, ap, imax, nonew, MatScalar); 459 } 460 N = nrow++ - 1; 461 a->nz++; 462 high++; 463 /* shift up all the later entries in this row */ 464 PetscCall(PetscArraymove(rp + i + 1, rp + i, N - i + 1)); 465 rp[i] = col; 466 if (!A->structure_only) { 467 PetscCall(PetscArraymove(ap + i + 1, ap + i, N - i + 1)); 468 ap[i] = value; 469 } 470 low = i + 1; 471 noinsert:; 472 } 473 ailen[row] = nrow; 474 } 475 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 476 PetscFunctionReturn(PETSC_SUCCESS); 477 } 478 479 static PetscErrorCode MatSetValues_SeqAIJ_SortedFullNoPreallocation(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is) 480 { 481 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 482 PetscInt *rp, k, row; 483 PetscInt *ai = a->i; 484 PetscInt *aj = a->j; 485 MatScalar *aa, *ap; 486 487 PetscFunctionBegin; 488 PetscCheck(!A->was_assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot call on assembled matrix."); 489 PetscCheck(m * n + a->nz <= a->maxnz, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of entries in matrix will be larger than maximum nonzeros allocated for %" PetscInt_FMT " in MatSeqAIJSetTotalPreallocation()", a->maxnz); 490 491 PetscCall(MatSeqAIJGetArray(A, &aa)); 492 for (k = 0; k < m; k++) { /* loop over added rows */ 493 row = im[k]; 494 rp = aj + ai[row]; 495 ap = PetscSafePointerPlusOffset(aa, ai[row]); 496 497 PetscCall(PetscMemcpy(rp, in, n * sizeof(PetscInt))); 498 if (!A->structure_only) { 499 if (v) { 500 PetscCall(PetscMemcpy(ap, v, n * sizeof(PetscScalar))); 501 v += n; 502 } else { 503 PetscCall(PetscMemzero(ap, n * sizeof(PetscScalar))); 504 } 505 } 506 a->ilen[row] = n; 507 a->imax[row] = n; 508 a->i[row + 1] = a->i[row] + n; 509 a->nz += n; 510 } 511 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 512 PetscFunctionReturn(PETSC_SUCCESS); 513 } 514 515 /*@ 516 MatSeqAIJSetTotalPreallocation - Sets an upper bound on the total number of expected nonzeros in the matrix. 517 518 Input Parameters: 519 + A - the `MATSEQAIJ` matrix 520 - nztotal - bound on the number of nonzeros 521 522 Level: advanced 523 524 Notes: 525 This can be called if you will be provided the matrix row by row (from row zero) with sorted column indices for each row. 526 Simply call `MatSetValues()` after this call to provide the matrix entries in the usual manner. This matrix may be used 527 as always with multiple matrix assemblies. 528 529 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MAT_SORTED_FULL`, `MatSetValues()`, `MatSeqAIJSetPreallocation()` 530 @*/ 531 PetscErrorCode MatSeqAIJSetTotalPreallocation(Mat A, PetscInt nztotal) 532 { 533 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 534 535 PetscFunctionBegin; 536 PetscCall(PetscLayoutSetUp(A->rmap)); 537 PetscCall(PetscLayoutSetUp(A->cmap)); 538 a->maxnz = nztotal; 539 if (!a->imax) { PetscCall(PetscMalloc1(A->rmap->n, &a->imax)); } 540 if (!a->ilen) { 541 PetscCall(PetscMalloc1(A->rmap->n, &a->ilen)); 542 } else { 543 PetscCall(PetscMemzero(a->ilen, A->rmap->n * sizeof(PetscInt))); 544 } 545 546 /* allocate the matrix space */ 547 PetscCall(PetscShmgetAllocateArray(A->rmap->n + 1, sizeof(PetscInt), (void **)&a->i)); 548 PetscCall(PetscShmgetAllocateArray(nztotal, sizeof(PetscInt), (void **)&a->j)); 549 a->free_ij = PETSC_TRUE; 550 if (A->structure_only) { 551 a->free_a = PETSC_FALSE; 552 } else { 553 PetscCall(PetscShmgetAllocateArray(nztotal, sizeof(PetscScalar), (void **)&a->a)); 554 a->free_a = PETSC_TRUE; 555 } 556 a->i[0] = 0; 557 A->ops->setvalues = MatSetValues_SeqAIJ_SortedFullNoPreallocation; 558 A->preallocated = PETSC_TRUE; 559 PetscFunctionReturn(PETSC_SUCCESS); 560 } 561 562 static PetscErrorCode MatSetValues_SeqAIJ_SortedFull(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is) 563 { 564 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 565 PetscInt *rp, k, row; 566 PetscInt *ai = a->i, *ailen = a->ilen; 567 PetscInt *aj = a->j; 568 MatScalar *aa, *ap; 569 570 PetscFunctionBegin; 571 PetscCall(MatSeqAIJGetArray(A, &aa)); 572 for (k = 0; k < m; k++) { /* loop over added rows */ 573 row = im[k]; 574 PetscCheck(n <= a->imax[row], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Preallocation for row %" PetscInt_FMT " does not match number of columns provided", n); 575 rp = aj + ai[row]; 576 ap = aa + ai[row]; 577 if (!A->was_assembled) PetscCall(PetscMemcpy(rp, in, n * sizeof(PetscInt))); 578 if (!A->structure_only) { 579 if (v) { 580 PetscCall(PetscMemcpy(ap, v, n * sizeof(PetscScalar))); 581 v += n; 582 } else { 583 PetscCall(PetscMemzero(ap, n * sizeof(PetscScalar))); 584 } 585 } 586 ailen[row] = n; 587 a->nz += n; 588 } 589 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 590 PetscFunctionReturn(PETSC_SUCCESS); 591 } 592 593 static PetscErrorCode MatGetValues_SeqAIJ(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], PetscScalar v[]) 594 { 595 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 596 PetscInt *rp, k, low, high, t, row, nrow, i, col, l, *aj = a->j; 597 PetscInt *ai = a->i, *ailen = a->ilen; 598 const MatScalar *ap, *aa; 599 600 PetscFunctionBegin; 601 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 602 for (k = 0; k < m; k++) { /* loop over rows */ 603 row = im[k]; 604 if (row < 0) { 605 v += n; 606 continue; 607 } /* negative row */ 608 PetscCheck(row < A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, row, A->rmap->n - 1); 609 rp = PetscSafePointerPlusOffset(aj, ai[row]); 610 ap = PetscSafePointerPlusOffset(aa, ai[row]); 611 nrow = ailen[row]; 612 for (l = 0; l < n; l++) { /* loop over columns */ 613 if (in[l] < 0) { 614 v++; 615 continue; 616 } /* negative column */ 617 PetscCheck(in[l] < A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column too large: col %" PetscInt_FMT " max %" PetscInt_FMT, in[l], A->cmap->n - 1); 618 col = in[l]; 619 high = nrow; 620 low = 0; /* assume unsorted */ 621 while (high - low > 5) { 622 t = (low + high) / 2; 623 if (rp[t] > col) high = t; 624 else low = t; 625 } 626 for (i = low; i < high; i++) { 627 if (rp[i] > col) break; 628 if (rp[i] == col) { 629 *v++ = ap[i]; 630 goto finished; 631 } 632 } 633 *v++ = 0.0; 634 finished:; 635 } 636 } 637 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 638 PetscFunctionReturn(PETSC_SUCCESS); 639 } 640 641 static PetscErrorCode MatView_SeqAIJ_Binary(Mat mat, PetscViewer viewer) 642 { 643 Mat_SeqAIJ *A = (Mat_SeqAIJ *)mat->data; 644 const PetscScalar *av; 645 PetscInt header[4], M, N, m, nz, i; 646 PetscInt *rowlens; 647 648 PetscFunctionBegin; 649 PetscCall(PetscViewerSetUp(viewer)); 650 651 M = mat->rmap->N; 652 N = mat->cmap->N; 653 m = mat->rmap->n; 654 nz = A->nz; 655 656 /* write matrix header */ 657 header[0] = MAT_FILE_CLASSID; 658 header[1] = M; 659 header[2] = N; 660 header[3] = nz; 661 PetscCall(PetscViewerBinaryWrite(viewer, header, 4, PETSC_INT)); 662 663 /* fill in and store row lengths */ 664 PetscCall(PetscMalloc1(m, &rowlens)); 665 for (i = 0; i < m; i++) rowlens[i] = A->i[i + 1] - A->i[i]; 666 if (PetscDefined(USE_DEBUG)) { 667 PetscInt mnz = 0; 668 669 for (i = 0; i < m; i++) mnz += rowlens[i]; 670 PetscCheck(nz == mnz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Row lens %" PetscInt_FMT " do not sum to nz %" PetscInt_FMT, mnz, nz); 671 } 672 PetscCall(PetscViewerBinaryWrite(viewer, rowlens, m, PETSC_INT)); 673 PetscCall(PetscFree(rowlens)); 674 /* store column indices */ 675 PetscCall(PetscViewerBinaryWrite(viewer, A->j, nz, PETSC_INT)); 676 /* store nonzero values */ 677 PetscCall(MatSeqAIJGetArrayRead(mat, &av)); 678 PetscCall(PetscViewerBinaryWrite(viewer, av, nz, PETSC_SCALAR)); 679 PetscCall(MatSeqAIJRestoreArrayRead(mat, &av)); 680 681 /* write block size option to the viewer's .info file */ 682 PetscCall(MatView_Binary_BlockSizes(mat, viewer)); 683 PetscFunctionReturn(PETSC_SUCCESS); 684 } 685 686 static PetscErrorCode MatView_SeqAIJ_ASCII_structonly(Mat A, PetscViewer viewer) 687 { 688 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 689 PetscInt i, k, m = A->rmap->N; 690 691 PetscFunctionBegin; 692 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 693 for (i = 0; i < m; i++) { 694 PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i)); 695 for (k = a->i[i]; k < a->i[i + 1]; k++) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ") ", a->j[k])); 696 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 697 } 698 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 699 PetscFunctionReturn(PETSC_SUCCESS); 700 } 701 702 extern PetscErrorCode MatSeqAIJFactorInfo_Matlab(Mat, PetscViewer); 703 704 static PetscErrorCode MatView_SeqAIJ_ASCII(Mat A, PetscViewer viewer) 705 { 706 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 707 const PetscScalar *av; 708 PetscInt i, j, m = A->rmap->n; 709 const char *name; 710 PetscViewerFormat format; 711 712 PetscFunctionBegin; 713 if (A->structure_only) { 714 PetscCall(MatView_SeqAIJ_ASCII_structonly(A, viewer)); 715 PetscFunctionReturn(PETSC_SUCCESS); 716 } 717 718 PetscCall(PetscViewerGetFormat(viewer, &format)); 719 // By petsc's rule, even PETSC_VIEWER_ASCII_INFO_DETAIL doesn't print matrix entries 720 if (format == PETSC_VIEWER_ASCII_FACTOR_INFO || format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) PetscFunctionReturn(PETSC_SUCCESS); 721 722 /* trigger copy to CPU if needed */ 723 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 724 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 725 if (format == PETSC_VIEWER_ASCII_MATLAB) { 726 PetscInt nofinalvalue = 0; 727 if (m && ((a->i[m] == a->i[m - 1]) || (a->j[a->nz - 1] != A->cmap->n - 1))) { 728 /* Need a dummy value to ensure the dimension of the matrix. */ 729 nofinalvalue = 1; 730 } 731 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 732 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Size = %" PetscInt_FMT " %" PetscInt_FMT " \n", m, A->cmap->n)); 733 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Nonzeros = %" PetscInt_FMT " \n", a->nz)); 734 #if defined(PETSC_USE_COMPLEX) 735 PetscCall(PetscViewerASCIIPrintf(viewer, "zzz = zeros(%" PetscInt_FMT ",4);\n", a->nz + nofinalvalue)); 736 #else 737 PetscCall(PetscViewerASCIIPrintf(viewer, "zzz = zeros(%" PetscInt_FMT ",3);\n", a->nz + nofinalvalue)); 738 #endif 739 PetscCall(PetscViewerASCIIPrintf(viewer, "zzz = [\n")); 740 741 for (i = 0; i < m; i++) { 742 for (j = a->i[i]; j < a->i[i + 1]; j++) { 743 #if defined(PETSC_USE_COMPLEX) 744 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %18.16e %18.16e\n", i + 1, a->j[j] + 1, (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 745 #else 746 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %18.16e\n", i + 1, a->j[j] + 1, (double)a->a[j])); 747 #endif 748 } 749 } 750 if (nofinalvalue) { 751 #if defined(PETSC_USE_COMPLEX) 752 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %18.16e %18.16e\n", m, A->cmap->n, 0., 0.)); 753 #else 754 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %18.16e\n", m, A->cmap->n, 0.0)); 755 #endif 756 } 757 PetscCall(PetscObjectGetName((PetscObject)A, &name)); 758 PetscCall(PetscViewerASCIIPrintf(viewer, "];\n %s = spconvert(zzz);\n", name)); 759 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 760 } else if (format == PETSC_VIEWER_ASCII_COMMON) { 761 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 762 for (i = 0; i < m; i++) { 763 PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i)); 764 for (j = a->i[i]; j < a->i[i + 1]; j++) { 765 #if defined(PETSC_USE_COMPLEX) 766 if (PetscImaginaryPart(a->a[j]) > 0.0 && PetscRealPart(a->a[j]) != 0.0) { 767 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 768 } else if (PetscImaginaryPart(a->a[j]) < 0.0 && PetscRealPart(a->a[j]) != 0.0) { 769 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)-PetscImaginaryPart(a->a[j]))); 770 } else if (PetscRealPart(a->a[j]) != 0.0) { 771 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(a->a[j]))); 772 } 773 #else 774 if (a->a[j] != 0.0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)a->a[j])); 775 #endif 776 } 777 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 778 } 779 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 780 } else if (format == PETSC_VIEWER_ASCII_SYMMODU) { 781 PetscInt nzd = 0, fshift = 1, *sptr; 782 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 783 PetscCall(PetscMalloc1(m + 1, &sptr)); 784 for (i = 0; i < m; i++) { 785 sptr[i] = nzd + 1; 786 for (j = a->i[i]; j < a->i[i + 1]; j++) { 787 if (a->j[j] >= i) { 788 #if defined(PETSC_USE_COMPLEX) 789 if (PetscImaginaryPart(a->a[j]) != 0.0 || PetscRealPart(a->a[j]) != 0.0) nzd++; 790 #else 791 if (a->a[j] != 0.0) nzd++; 792 #endif 793 } 794 } 795 } 796 sptr[m] = nzd + 1; 797 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT "\n\n", m, nzd)); 798 for (i = 0; i < m + 1; i += 6) { 799 if (i + 4 < m) { 800 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1], sptr[i + 2], sptr[i + 3], sptr[i + 4], sptr[i + 5])); 801 } else if (i + 3 < m) { 802 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1], sptr[i + 2], sptr[i + 3], sptr[i + 4])); 803 } else if (i + 2 < m) { 804 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1], sptr[i + 2], sptr[i + 3])); 805 } else if (i + 1 < m) { 806 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1], sptr[i + 2])); 807 } else if (i < m) { 808 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1])); 809 } else { 810 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "\n", sptr[i])); 811 } 812 } 813 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 814 PetscCall(PetscFree(sptr)); 815 for (i = 0; i < m; i++) { 816 for (j = a->i[i]; j < a->i[i + 1]; j++) { 817 if (a->j[j] >= i) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " ", a->j[j] + fshift)); 818 } 819 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 820 } 821 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 822 for (i = 0; i < m; i++) { 823 for (j = a->i[i]; j < a->i[i + 1]; j++) { 824 if (a->j[j] >= i) { 825 #if defined(PETSC_USE_COMPLEX) 826 if (PetscImaginaryPart(a->a[j]) != 0.0 || PetscRealPart(a->a[j]) != 0.0) PetscCall(PetscViewerASCIIPrintf(viewer, " %18.16e %18.16e ", (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 827 #else 828 if (a->a[j] != 0.0) PetscCall(PetscViewerASCIIPrintf(viewer, " %18.16e ", (double)a->a[j])); 829 #endif 830 } 831 } 832 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 833 } 834 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 835 } else if (format == PETSC_VIEWER_ASCII_DENSE) { 836 PetscInt cnt = 0, jcnt; 837 PetscScalar value; 838 #if defined(PETSC_USE_COMPLEX) 839 PetscBool realonly = PETSC_TRUE; 840 841 for (i = 0; i < a->i[m]; i++) { 842 if (PetscImaginaryPart(a->a[i]) != 0.0) { 843 realonly = PETSC_FALSE; 844 break; 845 } 846 } 847 #endif 848 849 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 850 for (i = 0; i < m; i++) { 851 jcnt = 0; 852 for (j = 0; j < A->cmap->n; j++) { 853 if (jcnt < a->i[i + 1] - a->i[i] && j == a->j[cnt]) { 854 value = a->a[cnt++]; 855 jcnt++; 856 } else { 857 value = 0.0; 858 } 859 #if defined(PETSC_USE_COMPLEX) 860 if (realonly) { 861 PetscCall(PetscViewerASCIIPrintf(viewer, " %7.5e ", (double)PetscRealPart(value))); 862 } else { 863 PetscCall(PetscViewerASCIIPrintf(viewer, " %7.5e+%7.5e i ", (double)PetscRealPart(value), (double)PetscImaginaryPart(value))); 864 } 865 #else 866 PetscCall(PetscViewerASCIIPrintf(viewer, " %7.5e ", (double)value)); 867 #endif 868 } 869 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 870 } 871 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 872 } else if (format == PETSC_VIEWER_ASCII_MATRIXMARKET) { 873 PetscInt fshift = 1; 874 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 875 #if defined(PETSC_USE_COMPLEX) 876 PetscCall(PetscViewerASCIIPrintf(viewer, "%%%%MatrixMarket matrix coordinate complex general\n")); 877 #else 878 PetscCall(PetscViewerASCIIPrintf(viewer, "%%%%MatrixMarket matrix coordinate real general\n")); 879 #endif 880 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", m, A->cmap->n, a->nz)); 881 for (i = 0; i < m; i++) { 882 for (j = a->i[i]; j < a->i[i + 1]; j++) { 883 #if defined(PETSC_USE_COMPLEX) 884 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %g %g\n", i + fshift, a->j[j] + fshift, (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 885 #else 886 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %g\n", i + fshift, a->j[j] + fshift, (double)a->a[j])); 887 #endif 888 } 889 } 890 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 891 } else { 892 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 893 if (A->factortype) { 894 for (i = 0; i < m; i++) { 895 PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i)); 896 /* L part */ 897 for (j = a->i[i]; j < a->i[i + 1]; j++) { 898 #if defined(PETSC_USE_COMPLEX) 899 if (PetscImaginaryPart(a->a[j]) > 0.0) { 900 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 901 } else if (PetscImaginaryPart(a->a[j]) < 0.0) { 902 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)(-PetscImaginaryPart(a->a[j])))); 903 } else { 904 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(a->a[j]))); 905 } 906 #else 907 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)a->a[j])); 908 #endif 909 } 910 /* diagonal */ 911 j = a->diag[i]; 912 #if defined(PETSC_USE_COMPLEX) 913 if (PetscImaginaryPart(a->a[j]) > 0.0) { 914 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(1 / a->a[j]), (double)PetscImaginaryPart(1 / a->a[j]))); 915 } else if (PetscImaginaryPart(a->a[j]) < 0.0) { 916 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(1 / a->a[j]), (double)(-PetscImaginaryPart(1 / a->a[j])))); 917 } else { 918 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(1 / a->a[j]))); 919 } 920 #else 921 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)(1 / a->a[j]))); 922 #endif 923 924 /* U part */ 925 for (j = a->diag[i + 1] + 1; j < a->diag[i]; j++) { 926 #if defined(PETSC_USE_COMPLEX) 927 if (PetscImaginaryPart(a->a[j]) > 0.0) { 928 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 929 } else if (PetscImaginaryPart(a->a[j]) < 0.0) { 930 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)(-PetscImaginaryPart(a->a[j])))); 931 } else { 932 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(a->a[j]))); 933 } 934 #else 935 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)a->a[j])); 936 #endif 937 } 938 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 939 } 940 } else { 941 for (i = 0; i < m; i++) { 942 PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i)); 943 for (j = a->i[i]; j < a->i[i + 1]; j++) { 944 #if defined(PETSC_USE_COMPLEX) 945 if (PetscImaginaryPart(a->a[j]) > 0.0) { 946 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 947 } else if (PetscImaginaryPart(a->a[j]) < 0.0) { 948 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)-PetscImaginaryPart(a->a[j]))); 949 } else { 950 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(a->a[j]))); 951 } 952 #else 953 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)a->a[j])); 954 #endif 955 } 956 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 957 } 958 } 959 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 960 } 961 PetscCall(PetscViewerFlush(viewer)); 962 PetscFunctionReturn(PETSC_SUCCESS); 963 } 964 965 #include <petscdraw.h> 966 static PetscErrorCode MatView_SeqAIJ_Draw_Zoom(PetscDraw draw, void *Aa) 967 { 968 Mat A = (Mat)Aa; 969 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 970 PetscInt i, j, m = A->rmap->n; 971 int color; 972 PetscReal xl, yl, xr, yr, x_l, x_r, y_l, y_r; 973 PetscViewer viewer; 974 PetscViewerFormat format; 975 const PetscScalar *aa; 976 977 PetscFunctionBegin; 978 PetscCall(PetscObjectQuery((PetscObject)A, "Zoomviewer", (PetscObject *)&viewer)); 979 PetscCall(PetscViewerGetFormat(viewer, &format)); 980 PetscCall(PetscDrawGetCoordinates(draw, &xl, &yl, &xr, &yr)); 981 982 /* loop over matrix elements drawing boxes */ 983 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 984 if (format != PETSC_VIEWER_DRAW_CONTOUR) { 985 PetscDrawCollectiveBegin(draw); 986 /* Blue for negative, Cyan for zero and Red for positive */ 987 color = PETSC_DRAW_BLUE; 988 for (i = 0; i < m; i++) { 989 y_l = m - i - 1.0; 990 y_r = y_l + 1.0; 991 for (j = a->i[i]; j < a->i[i + 1]; j++) { 992 x_l = a->j[j]; 993 x_r = x_l + 1.0; 994 if (PetscRealPart(aa[j]) >= 0.) continue; 995 PetscCall(PetscDrawRectangle(draw, x_l, y_l, x_r, y_r, color, color, color, color)); 996 } 997 } 998 color = PETSC_DRAW_CYAN; 999 for (i = 0; i < m; i++) { 1000 y_l = m - i - 1.0; 1001 y_r = y_l + 1.0; 1002 for (j = a->i[i]; j < a->i[i + 1]; j++) { 1003 x_l = a->j[j]; 1004 x_r = x_l + 1.0; 1005 if (aa[j] != 0.) continue; 1006 PetscCall(PetscDrawRectangle(draw, x_l, y_l, x_r, y_r, color, color, color, color)); 1007 } 1008 } 1009 color = PETSC_DRAW_RED; 1010 for (i = 0; i < m; i++) { 1011 y_l = m - i - 1.0; 1012 y_r = y_l + 1.0; 1013 for (j = a->i[i]; j < a->i[i + 1]; j++) { 1014 x_l = a->j[j]; 1015 x_r = x_l + 1.0; 1016 if (PetscRealPart(aa[j]) <= 0.) continue; 1017 PetscCall(PetscDrawRectangle(draw, x_l, y_l, x_r, y_r, color, color, color, color)); 1018 } 1019 } 1020 PetscDrawCollectiveEnd(draw); 1021 } else { 1022 /* use contour shading to indicate magnitude of values */ 1023 /* first determine max of all nonzero values */ 1024 PetscReal minv = 0.0, maxv = 0.0; 1025 PetscInt nz = a->nz, count = 0; 1026 PetscDraw popup; 1027 1028 for (i = 0; i < nz; i++) { 1029 if (PetscAbsScalar(aa[i]) > maxv) maxv = PetscAbsScalar(aa[i]); 1030 } 1031 if (minv >= maxv) maxv = minv + PETSC_SMALL; 1032 PetscCall(PetscDrawGetPopup(draw, &popup)); 1033 PetscCall(PetscDrawScalePopup(popup, minv, maxv)); 1034 1035 PetscDrawCollectiveBegin(draw); 1036 for (i = 0; i < m; i++) { 1037 y_l = m - i - 1.0; 1038 y_r = y_l + 1.0; 1039 for (j = a->i[i]; j < a->i[i + 1]; j++) { 1040 x_l = a->j[j]; 1041 x_r = x_l + 1.0; 1042 color = PetscDrawRealToColor(PetscAbsScalar(aa[count]), minv, maxv); 1043 PetscCall(PetscDrawRectangle(draw, x_l, y_l, x_r, y_r, color, color, color, color)); 1044 count++; 1045 } 1046 } 1047 PetscDrawCollectiveEnd(draw); 1048 } 1049 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 1050 PetscFunctionReturn(PETSC_SUCCESS); 1051 } 1052 1053 #include <petscdraw.h> 1054 static PetscErrorCode MatView_SeqAIJ_Draw(Mat A, PetscViewer viewer) 1055 { 1056 PetscDraw draw; 1057 PetscReal xr, yr, xl, yl, h, w; 1058 PetscBool isnull; 1059 1060 PetscFunctionBegin; 1061 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1062 PetscCall(PetscDrawIsNull(draw, &isnull)); 1063 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1064 1065 xr = A->cmap->n; 1066 yr = A->rmap->n; 1067 h = yr / 10.0; 1068 w = xr / 10.0; 1069 xr += w; 1070 yr += h; 1071 xl = -w; 1072 yl = -h; 1073 PetscCall(PetscDrawSetCoordinates(draw, xl, yl, xr, yr)); 1074 PetscCall(PetscObjectCompose((PetscObject)A, "Zoomviewer", (PetscObject)viewer)); 1075 PetscCall(PetscDrawZoom(draw, MatView_SeqAIJ_Draw_Zoom, A)); 1076 PetscCall(PetscObjectCompose((PetscObject)A, "Zoomviewer", NULL)); 1077 PetscCall(PetscDrawSave(draw)); 1078 PetscFunctionReturn(PETSC_SUCCESS); 1079 } 1080 1081 PetscErrorCode MatView_SeqAIJ(Mat A, PetscViewer viewer) 1082 { 1083 PetscBool iascii, isbinary, isdraw; 1084 1085 PetscFunctionBegin; 1086 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1087 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 1088 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1089 if (iascii) PetscCall(MatView_SeqAIJ_ASCII(A, viewer)); 1090 else if (isbinary) PetscCall(MatView_SeqAIJ_Binary(A, viewer)); 1091 else if (isdraw) PetscCall(MatView_SeqAIJ_Draw(A, viewer)); 1092 PetscCall(MatView_SeqAIJ_Inode(A, viewer)); 1093 PetscFunctionReturn(PETSC_SUCCESS); 1094 } 1095 1096 PetscErrorCode MatAssemblyEnd_SeqAIJ(Mat A, MatAssemblyType mode) 1097 { 1098 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1099 PetscInt fshift = 0, i, *ai = a->i, *aj = a->j, *imax = a->imax; 1100 PetscInt m = A->rmap->n, *ip, N, *ailen = a->ilen, rmax = 0, n; 1101 MatScalar *aa = a->a, *ap; 1102 PetscReal ratio = 0.6; 1103 1104 PetscFunctionBegin; 1105 if (mode == MAT_FLUSH_ASSEMBLY) PetscFunctionReturn(PETSC_SUCCESS); 1106 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 1107 if (A->was_assembled && A->ass_nonzerostate == A->nonzerostate) { 1108 /* we need to respect users asking to use or not the inodes routine in between matrix assemblies */ 1109 PetscCall(MatAssemblyEnd_SeqAIJ_Inode(A, mode)); 1110 PetscFunctionReturn(PETSC_SUCCESS); 1111 } 1112 1113 if (m) rmax = ailen[0]; /* determine row with most nonzeros */ 1114 for (i = 1; i < m; i++) { 1115 /* move each row back by the amount of empty slots (fshift) before it*/ 1116 fshift += imax[i - 1] - ailen[i - 1]; 1117 rmax = PetscMax(rmax, ailen[i]); 1118 if (fshift) { 1119 ip = aj + ai[i]; 1120 ap = aa + ai[i]; 1121 N = ailen[i]; 1122 PetscCall(PetscArraymove(ip - fshift, ip, N)); 1123 if (!A->structure_only) PetscCall(PetscArraymove(ap - fshift, ap, N)); 1124 } 1125 ai[i] = ai[i - 1] + ailen[i - 1]; 1126 } 1127 if (m) { 1128 fshift += imax[m - 1] - ailen[m - 1]; 1129 ai[m] = ai[m - 1] + ailen[m - 1]; 1130 } 1131 /* reset ilen and imax for each row */ 1132 a->nonzerorowcnt = 0; 1133 if (A->structure_only) { 1134 PetscCall(PetscFree(a->imax)); 1135 PetscCall(PetscFree(a->ilen)); 1136 } else { /* !A->structure_only */ 1137 for (i = 0; i < m; i++) { 1138 ailen[i] = imax[i] = ai[i + 1] - ai[i]; 1139 a->nonzerorowcnt += ((ai[i + 1] - ai[i]) > 0); 1140 } 1141 } 1142 a->nz = ai[m]; 1143 PetscCheck(!fshift || a->nounused != -1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unused space detected in matrix: %" PetscInt_FMT " X %" PetscInt_FMT ", %" PetscInt_FMT " unneeded", m, A->cmap->n, fshift); 1144 PetscCall(MatMarkDiagonal_SeqAIJ(A)); // since diagonal info is used a lot, it is helpful to set them up at the end of assembly 1145 a->diagonaldense = PETSC_TRUE; 1146 n = PetscMin(A->rmap->n, A->cmap->n); 1147 for (i = 0; i < n; i++) { 1148 if (a->diag[i] >= ai[i + 1]) { 1149 a->diagonaldense = PETSC_FALSE; 1150 break; 1151 } 1152 } 1153 PetscCall(PetscInfo(A, "Matrix size: %" PetscInt_FMT " X %" PetscInt_FMT "; storage space: %" PetscInt_FMT " unneeded,%" PetscInt_FMT " used\n", m, A->cmap->n, fshift, a->nz)); 1154 PetscCall(PetscInfo(A, "Number of mallocs during MatSetValues() is %" PetscInt_FMT "\n", a->reallocs)); 1155 PetscCall(PetscInfo(A, "Maximum nonzeros in any row is %" PetscInt_FMT "\n", rmax)); 1156 1157 A->info.mallocs += a->reallocs; 1158 a->reallocs = 0; 1159 A->info.nz_unneeded = (PetscReal)fshift; 1160 a->rmax = rmax; 1161 1162 if (!A->structure_only) PetscCall(MatCheckCompressedRow(A, a->nonzerorowcnt, &a->compressedrow, a->i, m, ratio)); 1163 PetscCall(MatAssemblyEnd_SeqAIJ_Inode(A, mode)); 1164 PetscFunctionReturn(PETSC_SUCCESS); 1165 } 1166 1167 static PetscErrorCode MatRealPart_SeqAIJ(Mat A) 1168 { 1169 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1170 PetscInt i, nz = a->nz; 1171 MatScalar *aa; 1172 1173 PetscFunctionBegin; 1174 PetscCall(MatSeqAIJGetArray(A, &aa)); 1175 for (i = 0; i < nz; i++) aa[i] = PetscRealPart(aa[i]); 1176 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 1177 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 1178 PetscFunctionReturn(PETSC_SUCCESS); 1179 } 1180 1181 static PetscErrorCode MatImaginaryPart_SeqAIJ(Mat A) 1182 { 1183 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1184 PetscInt i, nz = a->nz; 1185 MatScalar *aa; 1186 1187 PetscFunctionBegin; 1188 PetscCall(MatSeqAIJGetArray(A, &aa)); 1189 for (i = 0; i < nz; i++) aa[i] = PetscImaginaryPart(aa[i]); 1190 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 1191 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 1192 PetscFunctionReturn(PETSC_SUCCESS); 1193 } 1194 1195 PetscErrorCode MatZeroEntries_SeqAIJ(Mat A) 1196 { 1197 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1198 MatScalar *aa; 1199 1200 PetscFunctionBegin; 1201 PetscCall(MatSeqAIJGetArrayWrite(A, &aa)); 1202 PetscCall(PetscArrayzero(aa, a->i[A->rmap->n])); 1203 PetscCall(MatSeqAIJRestoreArrayWrite(A, &aa)); 1204 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 1205 PetscFunctionReturn(PETSC_SUCCESS); 1206 } 1207 1208 static PetscErrorCode MatReset_SeqAIJ(Mat A) 1209 { 1210 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1211 1212 PetscFunctionBegin; 1213 if (A->hash_active) { 1214 A->ops[0] = a->cops; 1215 PetscCall(PetscHMapIJVDestroy(&a->ht)); 1216 PetscCall(PetscFree(a->dnz)); 1217 A->hash_active = PETSC_FALSE; 1218 } 1219 1220 PetscCall(PetscLogObjectState((PetscObject)A, "Rows=%" PetscInt_FMT ", Cols=%" PetscInt_FMT ", NZ=%" PetscInt_FMT, A->rmap->n, A->cmap->n, a->nz)); 1221 PetscCall(MatSeqXAIJFreeAIJ(A, &a->a, &a->j, &a->i)); 1222 PetscCall(ISDestroy(&a->row)); 1223 PetscCall(ISDestroy(&a->col)); 1224 PetscCall(PetscFree(a->diag)); 1225 PetscCall(PetscFree(a->ibdiag)); 1226 PetscCall(PetscFree(a->imax)); 1227 PetscCall(PetscFree(a->ilen)); 1228 PetscCall(PetscFree(a->ipre)); 1229 PetscCall(PetscFree3(a->idiag, a->mdiag, a->ssor_work)); 1230 PetscCall(PetscFree(a->solve_work)); 1231 PetscCall(ISDestroy(&a->icol)); 1232 PetscCall(PetscFree(a->saved_values)); 1233 PetscCall(PetscFree2(a->compressedrow.i, a->compressedrow.rindex)); 1234 PetscCall(MatDestroy_SeqAIJ_Inode(A)); 1235 PetscFunctionReturn(PETSC_SUCCESS); 1236 } 1237 1238 static PetscErrorCode MatResetHash_SeqAIJ(Mat A) 1239 { 1240 PetscFunctionBegin; 1241 PetscCall(MatReset_SeqAIJ(A)); 1242 PetscCall(MatCreate_SeqAIJ_Inode(A)); 1243 PetscCall(MatSetUp_Seq_Hash(A)); 1244 A->nonzerostate++; 1245 PetscFunctionReturn(PETSC_SUCCESS); 1246 } 1247 1248 PetscErrorCode MatDestroy_SeqAIJ(Mat A) 1249 { 1250 PetscFunctionBegin; 1251 PetscCall(MatReset_SeqAIJ(A)); 1252 PetscCall(PetscFree(A->data)); 1253 1254 /* MatMatMultNumeric_SeqAIJ_SeqAIJ_Sorted may allocate this. 1255 That function is so heavily used (sometimes in an hidden way through multnumeric function pointers) 1256 that is hard to properly add this data to the MatProduct data. We free it here to avoid 1257 users reusing the matrix object with different data to incur in obscure segmentation faults 1258 due to different matrix sizes */ 1259 PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc__ab_dense", NULL)); 1260 1261 PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL)); 1262 PetscCall(PetscObjectComposeFunction((PetscObject)A, "PetscMatlabEnginePut_C", NULL)); 1263 PetscCall(PetscObjectComposeFunction((PetscObject)A, "PetscMatlabEngineGet_C", NULL)); 1264 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqAIJSetColumnIndices_C", NULL)); 1265 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatStoreValues_C", NULL)); 1266 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatRetrieveValues_C", NULL)); 1267 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqsbaij_C", NULL)); 1268 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqbaij_C", NULL)); 1269 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijperm_C", NULL)); 1270 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijsell_C", NULL)); 1271 #if defined(PETSC_HAVE_MKL_SPARSE) 1272 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijmkl_C", NULL)); 1273 #endif 1274 #if defined(PETSC_HAVE_CUDA) 1275 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijcusparse_C", NULL)); 1276 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaijcusparse_seqaij_C", NULL)); 1277 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaij_seqaijcusparse_C", NULL)); 1278 #endif 1279 #if defined(PETSC_HAVE_HIP) 1280 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijhipsparse_C", NULL)); 1281 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaijhipsparse_seqaij_C", NULL)); 1282 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaij_seqaijhipsparse_C", NULL)); 1283 #endif 1284 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 1285 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijkokkos_C", NULL)); 1286 #endif 1287 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijcrl_C", NULL)); 1288 #if defined(PETSC_HAVE_ELEMENTAL) 1289 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_elemental_C", NULL)); 1290 #endif 1291 #if defined(PETSC_HAVE_SCALAPACK) 1292 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_scalapack_C", NULL)); 1293 #endif 1294 #if defined(PETSC_HAVE_HYPRE) 1295 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_hypre_C", NULL)); 1296 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_transpose_seqaij_seqaij_C", NULL)); 1297 #endif 1298 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqdense_C", NULL)); 1299 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqsell_C", NULL)); 1300 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_is_C", NULL)); 1301 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatIsTranspose_C", NULL)); 1302 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatIsHermitianTranspose_C", NULL)); 1303 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqAIJSetPreallocation_C", NULL)); 1304 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatResetPreallocation_C", NULL)); 1305 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatResetHash_C", NULL)); 1306 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqAIJSetPreallocationCSR_C", NULL)); 1307 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatReorderForNonzeroDiagonal_C", NULL)); 1308 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_is_seqaij_C", NULL)); 1309 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqdense_seqaij_C", NULL)); 1310 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaij_seqaij_C", NULL)); 1311 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqAIJKron_C", NULL)); 1312 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", NULL)); 1313 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", NULL)); 1314 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatFactorGetSolverType_C", NULL)); 1315 /* these calls do not belong here: the subclasses Duplicate/Destroy are wrong */ 1316 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaijsell_seqaij_C", NULL)); 1317 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaijperm_seqaij_C", NULL)); 1318 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijviennacl_C", NULL)); 1319 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaijviennacl_seqdense_C", NULL)); 1320 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaijviennacl_seqaij_C", NULL)); 1321 PetscFunctionReturn(PETSC_SUCCESS); 1322 } 1323 1324 PetscErrorCode MatSetOption_SeqAIJ(Mat A, MatOption op, PetscBool flg) 1325 { 1326 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1327 1328 PetscFunctionBegin; 1329 switch (op) { 1330 case MAT_ROW_ORIENTED: 1331 a->roworiented = flg; 1332 break; 1333 case MAT_KEEP_NONZERO_PATTERN: 1334 a->keepnonzeropattern = flg; 1335 break; 1336 case MAT_NEW_NONZERO_LOCATIONS: 1337 a->nonew = (flg ? 0 : 1); 1338 break; 1339 case MAT_NEW_NONZERO_LOCATION_ERR: 1340 a->nonew = (flg ? -1 : 0); 1341 break; 1342 case MAT_NEW_NONZERO_ALLOCATION_ERR: 1343 a->nonew = (flg ? -2 : 0); 1344 break; 1345 case MAT_UNUSED_NONZERO_LOCATION_ERR: 1346 a->nounused = (flg ? -1 : 0); 1347 break; 1348 case MAT_IGNORE_ZERO_ENTRIES: 1349 a->ignorezeroentries = flg; 1350 break; 1351 case MAT_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++] = 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 > 0 && 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 2951 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 2952 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]); 2953 PetscCall(PetscArraycpy(b->a, aa, a->i[A->rmap->n])); 2954 PetscCall(PetscObjectStateIncrease((PetscObject)B)); 2955 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 2956 } else { 2957 PetscCall(MatCopy_Basic(A, B, str)); 2958 } 2959 PetscFunctionReturn(PETSC_SUCCESS); 2960 } 2961 2962 PETSC_INTERN PetscErrorCode MatSeqAIJGetArray_SeqAIJ(Mat A, PetscScalar *array[]) 2963 { 2964 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2965 2966 PetscFunctionBegin; 2967 *array = a->a; 2968 PetscFunctionReturn(PETSC_SUCCESS); 2969 } 2970 2971 PETSC_INTERN PetscErrorCode MatSeqAIJRestoreArray_SeqAIJ(Mat A, PetscScalar *array[]) 2972 { 2973 PetscFunctionBegin; 2974 *array = NULL; 2975 PetscFunctionReturn(PETSC_SUCCESS); 2976 } 2977 2978 /* 2979 Computes the number of nonzeros per row needed for preallocation when X and Y 2980 have different nonzero structure. 2981 */ 2982 PetscErrorCode MatAXPYGetPreallocation_SeqX_private(PetscInt m, const PetscInt *xi, const PetscInt *xj, const PetscInt *yi, const PetscInt *yj, PetscInt *nnz) 2983 { 2984 PetscInt i, j, k, nzx, nzy; 2985 2986 PetscFunctionBegin; 2987 /* Set the number of nonzeros in the new matrix */ 2988 for (i = 0; i < m; i++) { 2989 const PetscInt *xjj = PetscSafePointerPlusOffset(xj, xi[i]), *yjj = PetscSafePointerPlusOffset(yj, yi[i]); 2990 nzx = xi[i + 1] - xi[i]; 2991 nzy = yi[i + 1] - yi[i]; 2992 nnz[i] = 0; 2993 for (j = 0, k = 0; j < nzx; j++) { /* Point in X */ 2994 for (; k < nzy && yjj[k] < xjj[j]; k++) nnz[i]++; /* Catch up to X */ 2995 if (k < nzy && yjj[k] == xjj[j]) k++; /* Skip duplicate */ 2996 nnz[i]++; 2997 } 2998 for (; k < nzy; k++) nnz[i]++; 2999 } 3000 PetscFunctionReturn(PETSC_SUCCESS); 3001 } 3002 3003 PetscErrorCode MatAXPYGetPreallocation_SeqAIJ(Mat Y, Mat X, PetscInt *nnz) 3004 { 3005 PetscInt m = Y->rmap->N; 3006 Mat_SeqAIJ *x = (Mat_SeqAIJ *)X->data; 3007 Mat_SeqAIJ *y = (Mat_SeqAIJ *)Y->data; 3008 3009 PetscFunctionBegin; 3010 /* Set the number of nonzeros in the new matrix */ 3011 PetscCall(MatAXPYGetPreallocation_SeqX_private(m, x->i, x->j, y->i, y->j, nnz)); 3012 PetscFunctionReturn(PETSC_SUCCESS); 3013 } 3014 3015 PetscErrorCode MatAXPY_SeqAIJ(Mat Y, PetscScalar a, Mat X, MatStructure str) 3016 { 3017 Mat_SeqAIJ *x = (Mat_SeqAIJ *)X->data, *y = (Mat_SeqAIJ *)Y->data; 3018 3019 PetscFunctionBegin; 3020 if (str == UNKNOWN_NONZERO_PATTERN || (PetscDefined(USE_DEBUG) && str == SAME_NONZERO_PATTERN)) { 3021 PetscBool e = x->nz == y->nz ? PETSC_TRUE : PETSC_FALSE; 3022 if (e) { 3023 PetscCall(PetscArraycmp(x->i, y->i, Y->rmap->n + 1, &e)); 3024 if (e) { 3025 PetscCall(PetscArraycmp(x->j, y->j, y->nz, &e)); 3026 if (e) str = SAME_NONZERO_PATTERN; 3027 } 3028 } 3029 if (!e) PetscCheck(str != SAME_NONZERO_PATTERN, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MatStructure is not SAME_NONZERO_PATTERN"); 3030 } 3031 if (str == SAME_NONZERO_PATTERN) { 3032 const PetscScalar *xa; 3033 PetscScalar *ya, alpha = a; 3034 PetscBLASInt one = 1, bnz; 3035 3036 PetscCall(PetscBLASIntCast(x->nz, &bnz)); 3037 PetscCall(MatSeqAIJGetArray(Y, &ya)); 3038 PetscCall(MatSeqAIJGetArrayRead(X, &xa)); 3039 PetscCallBLAS("BLASaxpy", BLASaxpy_(&bnz, &alpha, xa, &one, ya, &one)); 3040 PetscCall(MatSeqAIJRestoreArrayRead(X, &xa)); 3041 PetscCall(MatSeqAIJRestoreArray(Y, &ya)); 3042 PetscCall(PetscLogFlops(2.0 * bnz)); 3043 PetscCall(MatSeqAIJInvalidateDiagonal(Y)); 3044 PetscCall(PetscObjectStateIncrease((PetscObject)Y)); 3045 } else if (str == SUBSET_NONZERO_PATTERN) { /* nonzeros of X is a subset of Y's */ 3046 PetscCall(MatAXPY_Basic(Y, a, X, str)); 3047 } else { 3048 Mat B; 3049 PetscInt *nnz; 3050 PetscCall(PetscMalloc1(Y->rmap->N, &nnz)); 3051 PetscCall(MatCreate(PetscObjectComm((PetscObject)Y), &B)); 3052 PetscCall(PetscObjectSetName((PetscObject)B, ((PetscObject)Y)->name)); 3053 PetscCall(MatSetLayouts(B, Y->rmap, Y->cmap)); 3054 PetscCall(MatSetType(B, ((PetscObject)Y)->type_name)); 3055 PetscCall(MatAXPYGetPreallocation_SeqAIJ(Y, X, nnz)); 3056 PetscCall(MatSeqAIJSetPreallocation(B, 0, nnz)); 3057 PetscCall(MatAXPY_BasicWithPreallocation(B, Y, a, X, str)); 3058 PetscCall(MatHeaderMerge(Y, &B)); 3059 PetscCall(MatSeqAIJCheckInode(Y)); 3060 PetscCall(PetscFree(nnz)); 3061 } 3062 PetscFunctionReturn(PETSC_SUCCESS); 3063 } 3064 3065 PETSC_INTERN PetscErrorCode MatConjugate_SeqAIJ(Mat mat) 3066 { 3067 #if defined(PETSC_USE_COMPLEX) 3068 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3069 PetscInt i, nz; 3070 PetscScalar *a; 3071 3072 PetscFunctionBegin; 3073 nz = aij->nz; 3074 PetscCall(MatSeqAIJGetArray(mat, &a)); 3075 for (i = 0; i < nz; i++) a[i] = PetscConj(a[i]); 3076 PetscCall(MatSeqAIJRestoreArray(mat, &a)); 3077 #else 3078 PetscFunctionBegin; 3079 #endif 3080 PetscFunctionReturn(PETSC_SUCCESS); 3081 } 3082 3083 static PetscErrorCode MatGetRowMaxAbs_SeqAIJ(Mat A, Vec v, PetscInt idx[]) 3084 { 3085 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3086 PetscInt i, j, m = A->rmap->n, *ai, *aj, ncols, n; 3087 PetscReal atmp; 3088 PetscScalar *x; 3089 const MatScalar *aa, *av; 3090 3091 PetscFunctionBegin; 3092 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3093 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3094 aa = av; 3095 ai = a->i; 3096 aj = a->j; 3097 3098 PetscCall(VecGetArrayWrite(v, &x)); 3099 PetscCall(VecGetLocalSize(v, &n)); 3100 PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 3101 for (i = 0; i < m; i++) { 3102 ncols = ai[1] - ai[0]; 3103 ai++; 3104 x[i] = 0; 3105 for (j = 0; j < ncols; j++) { 3106 atmp = PetscAbsScalar(*aa); 3107 if (PetscAbsScalar(x[i]) < atmp) { 3108 x[i] = atmp; 3109 if (idx) idx[i] = *aj; 3110 } 3111 aa++; 3112 aj++; 3113 } 3114 } 3115 PetscCall(VecRestoreArrayWrite(v, &x)); 3116 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3117 PetscFunctionReturn(PETSC_SUCCESS); 3118 } 3119 3120 static PetscErrorCode MatGetRowSumAbs_SeqAIJ(Mat A, Vec v) 3121 { 3122 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3123 PetscInt i, j, m = A->rmap->n, *ai, ncols, n; 3124 PetscScalar *x; 3125 const MatScalar *aa, *av; 3126 3127 PetscFunctionBegin; 3128 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3129 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3130 aa = av; 3131 ai = a->i; 3132 3133 PetscCall(VecGetArrayWrite(v, &x)); 3134 PetscCall(VecGetLocalSize(v, &n)); 3135 PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 3136 for (i = 0; i < m; i++) { 3137 ncols = ai[1] - ai[0]; 3138 ai++; 3139 x[i] = 0; 3140 for (j = 0; j < ncols; j++) { 3141 x[i] += PetscAbsScalar(*aa); 3142 aa++; 3143 } 3144 } 3145 PetscCall(VecRestoreArrayWrite(v, &x)); 3146 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3147 PetscFunctionReturn(PETSC_SUCCESS); 3148 } 3149 3150 static PetscErrorCode MatGetRowMax_SeqAIJ(Mat A, Vec v, PetscInt idx[]) 3151 { 3152 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3153 PetscInt i, j, m = A->rmap->n, *ai, *aj, ncols, n; 3154 PetscScalar *x; 3155 const MatScalar *aa, *av; 3156 3157 PetscFunctionBegin; 3158 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3159 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3160 aa = av; 3161 ai = a->i; 3162 aj = a->j; 3163 3164 PetscCall(VecGetArrayWrite(v, &x)); 3165 PetscCall(VecGetLocalSize(v, &n)); 3166 PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 3167 for (i = 0; i < m; i++) { 3168 ncols = ai[1] - ai[0]; 3169 ai++; 3170 if (ncols == A->cmap->n) { /* row is dense */ 3171 x[i] = *aa; 3172 if (idx) idx[i] = 0; 3173 } else { /* row is sparse so already KNOW maximum is 0.0 or higher */ 3174 x[i] = 0.0; 3175 if (idx) { 3176 for (j = 0; j < ncols; j++) { /* find first implicit 0.0 in the row */ 3177 if (aj[j] > j) { 3178 idx[i] = j; 3179 break; 3180 } 3181 } 3182 /* in case first implicit 0.0 in the row occurs at ncols-th column */ 3183 if (j == ncols && j < A->cmap->n) idx[i] = j; 3184 } 3185 } 3186 for (j = 0; j < ncols; j++) { 3187 if (PetscRealPart(x[i]) < PetscRealPart(*aa)) { 3188 x[i] = *aa; 3189 if (idx) idx[i] = *aj; 3190 } 3191 aa++; 3192 aj++; 3193 } 3194 } 3195 PetscCall(VecRestoreArrayWrite(v, &x)); 3196 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3197 PetscFunctionReturn(PETSC_SUCCESS); 3198 } 3199 3200 static PetscErrorCode MatGetRowMinAbs_SeqAIJ(Mat A, Vec v, PetscInt idx[]) 3201 { 3202 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3203 PetscInt i, j, m = A->rmap->n, *ai, *aj, ncols, n; 3204 PetscScalar *x; 3205 const MatScalar *aa, *av; 3206 3207 PetscFunctionBegin; 3208 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3209 aa = av; 3210 ai = a->i; 3211 aj = a->j; 3212 3213 PetscCall(VecGetArrayWrite(v, &x)); 3214 PetscCall(VecGetLocalSize(v, &n)); 3215 PetscCheck(n == m, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector, %" PetscInt_FMT " vs. %" PetscInt_FMT " rows", m, n); 3216 for (i = 0; i < m; i++) { 3217 ncols = ai[1] - ai[0]; 3218 ai++; 3219 if (ncols == A->cmap->n) { /* row is dense */ 3220 x[i] = *aa; 3221 if (idx) idx[i] = 0; 3222 } else { /* row is sparse so already KNOW minimum is 0.0 or higher */ 3223 x[i] = 0.0; 3224 if (idx) { /* find first implicit 0.0 in the row */ 3225 for (j = 0; j < ncols; j++) { 3226 if (aj[j] > j) { 3227 idx[i] = j; 3228 break; 3229 } 3230 } 3231 /* in case first implicit 0.0 in the row occurs at ncols-th column */ 3232 if (j == ncols && j < A->cmap->n) idx[i] = j; 3233 } 3234 } 3235 for (j = 0; j < ncols; j++) { 3236 if (PetscAbsScalar(x[i]) > PetscAbsScalar(*aa)) { 3237 x[i] = *aa; 3238 if (idx) idx[i] = *aj; 3239 } 3240 aa++; 3241 aj++; 3242 } 3243 } 3244 PetscCall(VecRestoreArrayWrite(v, &x)); 3245 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3246 PetscFunctionReturn(PETSC_SUCCESS); 3247 } 3248 3249 static PetscErrorCode MatGetRowMin_SeqAIJ(Mat A, Vec v, PetscInt idx[]) 3250 { 3251 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3252 PetscInt i, j, m = A->rmap->n, ncols, n; 3253 const PetscInt *ai, *aj; 3254 PetscScalar *x; 3255 const MatScalar *aa, *av; 3256 3257 PetscFunctionBegin; 3258 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3259 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3260 aa = av; 3261 ai = a->i; 3262 aj = a->j; 3263 3264 PetscCall(VecGetArrayWrite(v, &x)); 3265 PetscCall(VecGetLocalSize(v, &n)); 3266 PetscCheck(n == m, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 3267 for (i = 0; i < m; i++) { 3268 ncols = ai[1] - ai[0]; 3269 ai++; 3270 if (ncols == A->cmap->n) { /* row is dense */ 3271 x[i] = *aa; 3272 if (idx) idx[i] = 0; 3273 } else { /* row is sparse so already KNOW minimum is 0.0 or lower */ 3274 x[i] = 0.0; 3275 if (idx) { /* find first implicit 0.0 in the row */ 3276 for (j = 0; j < ncols; j++) { 3277 if (aj[j] > j) { 3278 idx[i] = j; 3279 break; 3280 } 3281 } 3282 /* in case first implicit 0.0 in the row occurs at ncols-th column */ 3283 if (j == ncols && j < A->cmap->n) idx[i] = j; 3284 } 3285 } 3286 for (j = 0; j < ncols; j++) { 3287 if (PetscRealPart(x[i]) > PetscRealPart(*aa)) { 3288 x[i] = *aa; 3289 if (idx) idx[i] = *aj; 3290 } 3291 aa++; 3292 aj++; 3293 } 3294 } 3295 PetscCall(VecRestoreArrayWrite(v, &x)); 3296 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3297 PetscFunctionReturn(PETSC_SUCCESS); 3298 } 3299 3300 static PetscErrorCode MatInvertBlockDiagonal_SeqAIJ(Mat A, const PetscScalar **values) 3301 { 3302 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3303 PetscInt i, bs = PetscAbs(A->rmap->bs), mbs = A->rmap->n / bs, ipvt[5], bs2 = bs * bs, *v_pivots, ij[7], *IJ, j; 3304 MatScalar *diag, work[25], *v_work; 3305 const PetscReal shift = 0.0; 3306 PetscBool allowzeropivot, zeropivotdetected = PETSC_FALSE; 3307 3308 PetscFunctionBegin; 3309 allowzeropivot = PetscNot(A->erroriffailure); 3310 if (a->ibdiagvalid) { 3311 if (values) *values = a->ibdiag; 3312 PetscFunctionReturn(PETSC_SUCCESS); 3313 } 3314 PetscCall(MatMarkDiagonal_SeqAIJ(A)); 3315 if (!a->ibdiag) { PetscCall(PetscMalloc1(bs2 * mbs, &a->ibdiag)); } 3316 diag = a->ibdiag; 3317 if (values) *values = a->ibdiag; 3318 /* factor and invert each block */ 3319 switch (bs) { 3320 case 1: 3321 for (i = 0; i < mbs; i++) { 3322 PetscCall(MatGetValues(A, 1, &i, 1, &i, diag + i)); 3323 if (PetscAbsScalar(diag[i] + shift) < PETSC_MACHINE_EPSILON) { 3324 if (allowzeropivot) { 3325 A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3326 A->factorerror_zeropivot_value = PetscAbsScalar(diag[i]); 3327 A->factorerror_zeropivot_row = i; 3328 PetscCall(PetscInfo(A, "Zero pivot, row %" PetscInt_FMT " pivot %g tolerance %g\n", i, (double)PetscAbsScalar(diag[i]), (double)PETSC_MACHINE_EPSILON)); 3329 } 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); 3330 } 3331 diag[i] = (PetscScalar)1.0 / (diag[i] + shift); 3332 } 3333 break; 3334 case 2: 3335 for (i = 0; i < mbs; i++) { 3336 ij[0] = 2 * i; 3337 ij[1] = 2 * i + 1; 3338 PetscCall(MatGetValues(A, 2, ij, 2, ij, diag)); 3339 PetscCall(PetscKernel_A_gets_inverse_A_2(diag, shift, allowzeropivot, &zeropivotdetected)); 3340 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3341 PetscCall(PetscKernel_A_gets_transpose_A_2(diag)); 3342 diag += 4; 3343 } 3344 break; 3345 case 3: 3346 for (i = 0; i < mbs; i++) { 3347 ij[0] = 3 * i; 3348 ij[1] = 3 * i + 1; 3349 ij[2] = 3 * i + 2; 3350 PetscCall(MatGetValues(A, 3, ij, 3, ij, diag)); 3351 PetscCall(PetscKernel_A_gets_inverse_A_3(diag, shift, allowzeropivot, &zeropivotdetected)); 3352 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3353 PetscCall(PetscKernel_A_gets_transpose_A_3(diag)); 3354 diag += 9; 3355 } 3356 break; 3357 case 4: 3358 for (i = 0; i < mbs; i++) { 3359 ij[0] = 4 * i; 3360 ij[1] = 4 * i + 1; 3361 ij[2] = 4 * i + 2; 3362 ij[3] = 4 * i + 3; 3363 PetscCall(MatGetValues(A, 4, ij, 4, ij, diag)); 3364 PetscCall(PetscKernel_A_gets_inverse_A_4(diag, shift, allowzeropivot, &zeropivotdetected)); 3365 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3366 PetscCall(PetscKernel_A_gets_transpose_A_4(diag)); 3367 diag += 16; 3368 } 3369 break; 3370 case 5: 3371 for (i = 0; i < mbs; i++) { 3372 ij[0] = 5 * i; 3373 ij[1] = 5 * i + 1; 3374 ij[2] = 5 * i + 2; 3375 ij[3] = 5 * i + 3; 3376 ij[4] = 5 * i + 4; 3377 PetscCall(MatGetValues(A, 5, ij, 5, ij, diag)); 3378 PetscCall(PetscKernel_A_gets_inverse_A_5(diag, ipvt, work, shift, allowzeropivot, &zeropivotdetected)); 3379 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3380 PetscCall(PetscKernel_A_gets_transpose_A_5(diag)); 3381 diag += 25; 3382 } 3383 break; 3384 case 6: 3385 for (i = 0; i < mbs; i++) { 3386 ij[0] = 6 * i; 3387 ij[1] = 6 * i + 1; 3388 ij[2] = 6 * i + 2; 3389 ij[3] = 6 * i + 3; 3390 ij[4] = 6 * i + 4; 3391 ij[5] = 6 * i + 5; 3392 PetscCall(MatGetValues(A, 6, ij, 6, ij, diag)); 3393 PetscCall(PetscKernel_A_gets_inverse_A_6(diag, shift, allowzeropivot, &zeropivotdetected)); 3394 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3395 PetscCall(PetscKernel_A_gets_transpose_A_6(diag)); 3396 diag += 36; 3397 } 3398 break; 3399 case 7: 3400 for (i = 0; i < mbs; i++) { 3401 ij[0] = 7 * i; 3402 ij[1] = 7 * i + 1; 3403 ij[2] = 7 * i + 2; 3404 ij[3] = 7 * i + 3; 3405 ij[4] = 7 * i + 4; 3406 ij[5] = 7 * i + 5; 3407 ij[6] = 7 * i + 6; 3408 PetscCall(MatGetValues(A, 7, ij, 7, ij, diag)); 3409 PetscCall(PetscKernel_A_gets_inverse_A_7(diag, shift, allowzeropivot, &zeropivotdetected)); 3410 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3411 PetscCall(PetscKernel_A_gets_transpose_A_7(diag)); 3412 diag += 49; 3413 } 3414 break; 3415 default: 3416 PetscCall(PetscMalloc3(bs, &v_work, bs, &v_pivots, bs, &IJ)); 3417 for (i = 0; i < mbs; i++) { 3418 for (j = 0; j < bs; j++) IJ[j] = bs * i + j; 3419 PetscCall(MatGetValues(A, bs, IJ, bs, IJ, diag)); 3420 PetscCall(PetscKernel_A_gets_inverse_A(bs, diag, v_pivots, v_work, allowzeropivot, &zeropivotdetected)); 3421 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3422 PetscCall(PetscKernel_A_gets_transpose_A_N(diag, bs)); 3423 diag += bs2; 3424 } 3425 PetscCall(PetscFree3(v_work, v_pivots, IJ)); 3426 } 3427 a->ibdiagvalid = PETSC_TRUE; 3428 PetscFunctionReturn(PETSC_SUCCESS); 3429 } 3430 3431 static PetscErrorCode MatSetRandom_SeqAIJ(Mat x, PetscRandom rctx) 3432 { 3433 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)x->data; 3434 PetscScalar a, *aa; 3435 PetscInt m, n, i, j, col; 3436 3437 PetscFunctionBegin; 3438 if (!x->assembled) { 3439 PetscCall(MatGetSize(x, &m, &n)); 3440 for (i = 0; i < m; i++) { 3441 for (j = 0; j < aij->imax[i]; j++) { 3442 PetscCall(PetscRandomGetValue(rctx, &a)); 3443 col = (PetscInt)(n * PetscRealPart(a)); 3444 PetscCall(MatSetValues(x, 1, &i, 1, &col, &a, ADD_VALUES)); 3445 } 3446 } 3447 } else { 3448 PetscCall(MatSeqAIJGetArrayWrite(x, &aa)); 3449 for (i = 0; i < aij->nz; i++) PetscCall(PetscRandomGetValue(rctx, aa + i)); 3450 PetscCall(MatSeqAIJRestoreArrayWrite(x, &aa)); 3451 } 3452 PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY)); 3453 PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY)); 3454 PetscFunctionReturn(PETSC_SUCCESS); 3455 } 3456 3457 /* Like MatSetRandom_SeqAIJ, but do not set values on columns in range of [low, high) */ 3458 PetscErrorCode MatSetRandomSkipColumnRange_SeqAIJ_Private(Mat x, PetscInt low, PetscInt high, PetscRandom rctx) 3459 { 3460 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)x->data; 3461 PetscScalar a; 3462 PetscInt m, n, i, j, col, nskip; 3463 3464 PetscFunctionBegin; 3465 nskip = high - low; 3466 PetscCall(MatGetSize(x, &m, &n)); 3467 n -= nskip; /* shrink number of columns where nonzeros can be set */ 3468 for (i = 0; i < m; i++) { 3469 for (j = 0; j < aij->imax[i]; j++) { 3470 PetscCall(PetscRandomGetValue(rctx, &a)); 3471 col = (PetscInt)(n * PetscRealPart(a)); 3472 if (col >= low) col += nskip; /* shift col rightward to skip the hole */ 3473 PetscCall(MatSetValues(x, 1, &i, 1, &col, &a, ADD_VALUES)); 3474 } 3475 } 3476 PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY)); 3477 PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY)); 3478 PetscFunctionReturn(PETSC_SUCCESS); 3479 } 3480 3481 static struct _MatOps MatOps_Values = {MatSetValues_SeqAIJ, 3482 MatGetRow_SeqAIJ, 3483 MatRestoreRow_SeqAIJ, 3484 MatMult_SeqAIJ, 3485 /* 4*/ MatMultAdd_SeqAIJ, 3486 MatMultTranspose_SeqAIJ, 3487 MatMultTransposeAdd_SeqAIJ, 3488 NULL, 3489 NULL, 3490 NULL, 3491 /* 10*/ NULL, 3492 MatLUFactor_SeqAIJ, 3493 NULL, 3494 MatSOR_SeqAIJ, 3495 MatTranspose_SeqAIJ, 3496 /*1 5*/ MatGetInfo_SeqAIJ, 3497 MatEqual_SeqAIJ, 3498 MatGetDiagonal_SeqAIJ, 3499 MatDiagonalScale_SeqAIJ, 3500 MatNorm_SeqAIJ, 3501 /* 20*/ NULL, 3502 MatAssemblyEnd_SeqAIJ, 3503 MatSetOption_SeqAIJ, 3504 MatZeroEntries_SeqAIJ, 3505 /* 24*/ MatZeroRows_SeqAIJ, 3506 NULL, 3507 NULL, 3508 NULL, 3509 NULL, 3510 /* 29*/ MatSetUp_Seq_Hash, 3511 NULL, 3512 NULL, 3513 NULL, 3514 NULL, 3515 /* 34*/ MatDuplicate_SeqAIJ, 3516 NULL, 3517 NULL, 3518 MatILUFactor_SeqAIJ, 3519 NULL, 3520 /* 39*/ MatAXPY_SeqAIJ, 3521 MatCreateSubMatrices_SeqAIJ, 3522 MatIncreaseOverlap_SeqAIJ, 3523 MatGetValues_SeqAIJ, 3524 MatCopy_SeqAIJ, 3525 /* 44*/ MatGetRowMax_SeqAIJ, 3526 MatScale_SeqAIJ, 3527 MatShift_SeqAIJ, 3528 MatDiagonalSet_SeqAIJ, 3529 MatZeroRowsColumns_SeqAIJ, 3530 /* 49*/ MatSetRandom_SeqAIJ, 3531 MatGetRowIJ_SeqAIJ, 3532 MatRestoreRowIJ_SeqAIJ, 3533 MatGetColumnIJ_SeqAIJ, 3534 MatRestoreColumnIJ_SeqAIJ, 3535 /* 54*/ MatFDColoringCreate_SeqXAIJ, 3536 NULL, 3537 NULL, 3538 MatPermute_SeqAIJ, 3539 NULL, 3540 /* 59*/ NULL, 3541 MatDestroy_SeqAIJ, 3542 MatView_SeqAIJ, 3543 NULL, 3544 NULL, 3545 /* 64*/ NULL, 3546 MatMatMatMultNumeric_SeqAIJ_SeqAIJ_SeqAIJ, 3547 NULL, 3548 NULL, 3549 NULL, 3550 /* 69*/ MatGetRowMaxAbs_SeqAIJ, 3551 MatGetRowMinAbs_SeqAIJ, 3552 NULL, 3553 NULL, 3554 NULL, 3555 /* 74*/ NULL, 3556 MatFDColoringApply_AIJ, 3557 NULL, 3558 NULL, 3559 NULL, 3560 /* 79*/ MatFindZeroDiagonals_SeqAIJ, 3561 NULL, 3562 NULL, 3563 NULL, 3564 MatLoad_SeqAIJ, 3565 /* 84*/ NULL, 3566 NULL, 3567 NULL, 3568 NULL, 3569 NULL, 3570 /* 89*/ NULL, 3571 NULL, 3572 MatMatMultNumeric_SeqAIJ_SeqAIJ, 3573 NULL, 3574 NULL, 3575 /* 94*/ MatPtAPNumeric_SeqAIJ_SeqAIJ_SparseAxpy, 3576 NULL, 3577 NULL, 3578 MatMatTransposeMultNumeric_SeqAIJ_SeqAIJ, 3579 NULL, 3580 /* 99*/ MatProductSetFromOptions_SeqAIJ, 3581 NULL, 3582 NULL, 3583 MatConjugate_SeqAIJ, 3584 NULL, 3585 /*104*/ MatSetValuesRow_SeqAIJ, 3586 MatRealPart_SeqAIJ, 3587 MatImaginaryPart_SeqAIJ, 3588 NULL, 3589 NULL, 3590 /*109*/ MatMatSolve_SeqAIJ, 3591 NULL, 3592 MatGetRowMin_SeqAIJ, 3593 NULL, 3594 MatMissingDiagonal_SeqAIJ, 3595 /*114*/ NULL, 3596 NULL, 3597 NULL, 3598 NULL, 3599 NULL, 3600 /*119*/ NULL, 3601 NULL, 3602 NULL, 3603 NULL, 3604 MatGetMultiProcBlock_SeqAIJ, 3605 /*124*/ MatFindNonzeroRows_SeqAIJ, 3606 MatGetColumnReductions_SeqAIJ, 3607 MatInvertBlockDiagonal_SeqAIJ, 3608 MatInvertVariableBlockDiagonal_SeqAIJ, 3609 NULL, 3610 /*129*/ NULL, 3611 NULL, 3612 NULL, 3613 MatTransposeMatMultNumeric_SeqAIJ_SeqAIJ, 3614 MatTransposeColoringCreate_SeqAIJ, 3615 /*134*/ MatTransColoringApplySpToDen_SeqAIJ, 3616 MatTransColoringApplyDenToSp_SeqAIJ, 3617 NULL, 3618 NULL, 3619 MatRARtNumeric_SeqAIJ_SeqAIJ, 3620 /*139*/ NULL, 3621 NULL, 3622 NULL, 3623 MatFDColoringSetUp_SeqXAIJ, 3624 MatFindOffBlockDiagonalEntries_SeqAIJ, 3625 MatCreateMPIMatConcatenateSeqMat_SeqAIJ, 3626 /*145*/ MatDestroySubMatrices_SeqAIJ, 3627 NULL, 3628 NULL, 3629 MatCreateGraph_Simple_AIJ, 3630 NULL, 3631 /*150*/ MatTransposeSymbolic_SeqAIJ, 3632 MatEliminateZeros_SeqAIJ, 3633 MatGetRowSumAbs_SeqAIJ, 3634 NULL, 3635 NULL, 3636 /*155*/ NULL, 3637 MatCopyHashToXAIJ_Seq_Hash}; 3638 3639 static PetscErrorCode MatSeqAIJSetColumnIndices_SeqAIJ(Mat mat, PetscInt *indices) 3640 { 3641 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3642 PetscInt i, nz, n; 3643 3644 PetscFunctionBegin; 3645 nz = aij->maxnz; 3646 n = mat->rmap->n; 3647 for (i = 0; i < nz; i++) aij->j[i] = indices[i]; 3648 aij->nz = nz; 3649 for (i = 0; i < n; i++) aij->ilen[i] = aij->imax[i]; 3650 PetscFunctionReturn(PETSC_SUCCESS); 3651 } 3652 3653 /* 3654 * Given a sparse matrix with global column indices, compact it by using a local column space. 3655 * The result matrix helps saving memory in other algorithms, such as MatPtAPSymbolic_MPIAIJ_MPIAIJ_scalable() 3656 */ 3657 PetscErrorCode MatSeqAIJCompactOutExtraColumns_SeqAIJ(Mat mat, ISLocalToGlobalMapping *mapping) 3658 { 3659 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3660 PetscHMapI gid1_lid1; 3661 PetscHashIter tpos; 3662 PetscInt gid, lid, i, ec, nz = aij->nz; 3663 PetscInt *garray, *jj = aij->j; 3664 3665 PetscFunctionBegin; 3666 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3667 PetscAssertPointer(mapping, 2); 3668 /* use a table */ 3669 PetscCall(PetscHMapICreateWithSize(mat->rmap->n, &gid1_lid1)); 3670 ec = 0; 3671 for (i = 0; i < nz; i++) { 3672 PetscInt data, gid1 = jj[i] + 1; 3673 PetscCall(PetscHMapIGetWithDefault(gid1_lid1, gid1, 0, &data)); 3674 if (!data) { 3675 /* one based table */ 3676 PetscCall(PetscHMapISet(gid1_lid1, gid1, ++ec)); 3677 } 3678 } 3679 /* form array of columns we need */ 3680 PetscCall(PetscMalloc1(ec, &garray)); 3681 PetscHashIterBegin(gid1_lid1, tpos); 3682 while (!PetscHashIterAtEnd(gid1_lid1, tpos)) { 3683 PetscHashIterGetKey(gid1_lid1, tpos, gid); 3684 PetscHashIterGetVal(gid1_lid1, tpos, lid); 3685 PetscHashIterNext(gid1_lid1, tpos); 3686 gid--; 3687 lid--; 3688 garray[lid] = gid; 3689 } 3690 PetscCall(PetscSortInt(ec, garray)); /* sort, and rebuild */ 3691 PetscCall(PetscHMapIClear(gid1_lid1)); 3692 for (i = 0; i < ec; i++) PetscCall(PetscHMapISet(gid1_lid1, garray[i] + 1, i + 1)); 3693 /* compact out the extra columns in B */ 3694 for (i = 0; i < nz; i++) { 3695 PetscInt gid1 = jj[i] + 1; 3696 PetscCall(PetscHMapIGetWithDefault(gid1_lid1, gid1, 0, &lid)); 3697 lid--; 3698 jj[i] = lid; 3699 } 3700 PetscCall(PetscLayoutDestroy(&mat->cmap)); 3701 PetscCall(PetscHMapIDestroy(&gid1_lid1)); 3702 PetscCall(PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)mat), ec, ec, 1, &mat->cmap)); 3703 PetscCall(ISLocalToGlobalMappingCreate(PETSC_COMM_SELF, mat->cmap->bs, mat->cmap->n, garray, PETSC_OWN_POINTER, mapping)); 3704 PetscCall(ISLocalToGlobalMappingSetType(*mapping, ISLOCALTOGLOBALMAPPINGHASH)); 3705 PetscFunctionReturn(PETSC_SUCCESS); 3706 } 3707 3708 /*@ 3709 MatSeqAIJSetColumnIndices - Set the column indices for all the rows 3710 in the matrix. 3711 3712 Input Parameters: 3713 + mat - the `MATSEQAIJ` matrix 3714 - indices - the column indices 3715 3716 Level: advanced 3717 3718 Notes: 3719 This can be called if you have precomputed the nonzero structure of the 3720 matrix and want to provide it to the matrix object to improve the performance 3721 of the `MatSetValues()` operation. 3722 3723 You MUST have set the correct numbers of nonzeros per row in the call to 3724 `MatCreateSeqAIJ()`, and the columns indices MUST be sorted. 3725 3726 MUST be called before any calls to `MatSetValues()` 3727 3728 The indices should start with zero, not one. 3729 3730 .seealso: [](ch_matrices), `Mat`, `MATSEQAIJ` 3731 @*/ 3732 PetscErrorCode MatSeqAIJSetColumnIndices(Mat mat, PetscInt *indices) 3733 { 3734 PetscFunctionBegin; 3735 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3736 PetscAssertPointer(indices, 2); 3737 PetscUseMethod(mat, "MatSeqAIJSetColumnIndices_C", (Mat, PetscInt *), (mat, indices)); 3738 PetscFunctionReturn(PETSC_SUCCESS); 3739 } 3740 3741 static PetscErrorCode MatStoreValues_SeqAIJ(Mat mat) 3742 { 3743 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3744 size_t nz = aij->i[mat->rmap->n]; 3745 3746 PetscFunctionBegin; 3747 PetscCheck(aij->nonew, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first"); 3748 3749 /* allocate space for values if not already there */ 3750 if (!aij->saved_values) { PetscCall(PetscMalloc1(nz + 1, &aij->saved_values)); } 3751 3752 /* copy values over */ 3753 PetscCall(PetscArraycpy(aij->saved_values, aij->a, nz)); 3754 PetscFunctionReturn(PETSC_SUCCESS); 3755 } 3756 3757 /*@ 3758 MatStoreValues - Stashes a copy of the matrix values; this allows reusing of the linear part of a Jacobian, while recomputing only the 3759 nonlinear portion. 3760 3761 Logically Collect 3762 3763 Input Parameter: 3764 . mat - the matrix (currently only `MATAIJ` matrices support this option) 3765 3766 Level: advanced 3767 3768 Example Usage: 3769 .vb 3770 Using SNES 3771 Create Jacobian matrix 3772 Set linear terms into matrix 3773 Apply boundary conditions to matrix, at this time matrix must have 3774 final nonzero structure (i.e. setting the nonlinear terms and applying 3775 boundary conditions again will not change the nonzero structure 3776 MatSetOption(mat, MAT_NEW_NONZERO_LOCATIONS, PETSC_FALSE); 3777 MatStoreValues(mat); 3778 Call SNESSetJacobian() with matrix 3779 In your Jacobian routine 3780 MatRetrieveValues(mat); 3781 Set nonlinear terms in matrix 3782 3783 Without `SNESSolve()`, i.e. when you handle nonlinear solve yourself: 3784 // build linear portion of Jacobian 3785 MatSetOption(mat, MAT_NEW_NONZERO_LOCATIONS, PETSC_FALSE); 3786 MatStoreValues(mat); 3787 loop over nonlinear iterations 3788 MatRetrieveValues(mat); 3789 // call MatSetValues(mat,...) to set nonliner portion of Jacobian 3790 // call MatAssemblyBegin/End() on matrix 3791 Solve linear system with Jacobian 3792 endloop 3793 .ve 3794 3795 Notes: 3796 Matrix must already be assembled before calling this routine 3797 Must set the matrix option `MatSetOption`(mat,`MAT_NEW_NONZERO_LOCATIONS`,`PETSC_FALSE`); before 3798 calling this routine. 3799 3800 When this is called multiple times it overwrites the previous set of stored values 3801 and does not allocated additional space. 3802 3803 .seealso: [](ch_matrices), `Mat`, `MatRetrieveValues()` 3804 @*/ 3805 PetscErrorCode MatStoreValues(Mat mat) 3806 { 3807 PetscFunctionBegin; 3808 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3809 PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 3810 PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3811 PetscUseMethod(mat, "MatStoreValues_C", (Mat), (mat)); 3812 PetscFunctionReturn(PETSC_SUCCESS); 3813 } 3814 3815 static PetscErrorCode MatRetrieveValues_SeqAIJ(Mat mat) 3816 { 3817 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3818 PetscInt nz = aij->i[mat->rmap->n]; 3819 3820 PetscFunctionBegin; 3821 PetscCheck(aij->nonew, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first"); 3822 PetscCheck(aij->saved_values, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatStoreValues(A);first"); 3823 /* copy values over */ 3824 PetscCall(PetscArraycpy(aij->a, aij->saved_values, nz)); 3825 PetscFunctionReturn(PETSC_SUCCESS); 3826 } 3827 3828 /*@ 3829 MatRetrieveValues - Retrieves the copy of the matrix values that was stored with `MatStoreValues()` 3830 3831 Logically Collect 3832 3833 Input Parameter: 3834 . mat - the matrix (currently only `MATAIJ` matrices support this option) 3835 3836 Level: advanced 3837 3838 .seealso: [](ch_matrices), `Mat`, `MatStoreValues()` 3839 @*/ 3840 PetscErrorCode MatRetrieveValues(Mat mat) 3841 { 3842 PetscFunctionBegin; 3843 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3844 PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 3845 PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3846 PetscUseMethod(mat, "MatRetrieveValues_C", (Mat), (mat)); 3847 PetscFunctionReturn(PETSC_SUCCESS); 3848 } 3849 3850 /*@ 3851 MatCreateSeqAIJ - Creates a sparse matrix in `MATSEQAIJ` (compressed row) format 3852 (the default parallel PETSc format). For good matrix assembly performance 3853 the user should preallocate the matrix storage by setting the parameter `nz` 3854 (or the array `nnz`). 3855 3856 Collective 3857 3858 Input Parameters: 3859 + comm - MPI communicator, set to `PETSC_COMM_SELF` 3860 . m - number of rows 3861 . n - number of columns 3862 . nz - number of nonzeros per row (same for all rows) 3863 - nnz - array containing the number of nonzeros in the various rows 3864 (possibly different for each row) or NULL 3865 3866 Output Parameter: 3867 . A - the matrix 3868 3869 Options Database Keys: 3870 + -mat_no_inode - Do not use inodes 3871 - -mat_inode_limit <limit> - Sets inode limit (max limit=5) 3872 3873 Level: intermediate 3874 3875 Notes: 3876 It is recommend to use `MatCreateFromOptions()` instead of this routine 3877 3878 If `nnz` is given then `nz` is ignored 3879 3880 The `MATSEQAIJ` format, also called 3881 compressed row storage, is fully compatible with standard Fortran 3882 storage. That is, the stored row and column indices can begin at 3883 either one (as in Fortran) or zero. 3884 3885 Specify the preallocated storage with either `nz` or `nnz` (not both). 3886 Set `nz` = `PETSC_DEFAULT` and `nnz` = `NULL` for PETSc to control dynamic memory 3887 allocation. 3888 3889 By default, this format uses inodes (identical nodes) when possible, to 3890 improve numerical efficiency of matrix-vector products and solves. We 3891 search for consecutive rows with the same nonzero structure, thereby 3892 reusing matrix information to achieve increased efficiency. 3893 3894 .seealso: [](ch_matrices), `Mat`, [Sparse Matrix Creation](sec_matsparse), `MatCreate()`, `MatCreateAIJ()`, `MatSetValues()`, `MatSeqAIJSetColumnIndices()`, `MatCreateSeqAIJWithArrays()` 3895 @*/ 3896 PetscErrorCode MatCreateSeqAIJ(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt nz, const PetscInt nnz[], Mat *A) 3897 { 3898 PetscFunctionBegin; 3899 PetscCall(MatCreate(comm, A)); 3900 PetscCall(MatSetSizes(*A, m, n, m, n)); 3901 PetscCall(MatSetType(*A, MATSEQAIJ)); 3902 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*A, nz, nnz)); 3903 PetscFunctionReturn(PETSC_SUCCESS); 3904 } 3905 3906 /*@ 3907 MatSeqAIJSetPreallocation - For good matrix assembly performance 3908 the user should preallocate the matrix storage by setting the parameter nz 3909 (or the array nnz). By setting these parameters accurately, performance 3910 during matrix assembly can be increased by more than a factor of 50. 3911 3912 Collective 3913 3914 Input Parameters: 3915 + B - The matrix 3916 . nz - number of nonzeros per row (same for all rows) 3917 - nnz - array containing the number of nonzeros in the various rows 3918 (possibly different for each row) or NULL 3919 3920 Options Database Keys: 3921 + -mat_no_inode - Do not use inodes 3922 - -mat_inode_limit <limit> - Sets inode limit (max limit=5) 3923 3924 Level: intermediate 3925 3926 Notes: 3927 If `nnz` is given then `nz` is ignored 3928 3929 The `MATSEQAIJ` format also called 3930 compressed row storage, is fully compatible with standard Fortran 3931 storage. That is, the stored row and column indices can begin at 3932 either one (as in Fortran) or zero. See the users' manual for details. 3933 3934 Specify the preallocated storage with either `nz` or `nnz` (not both). 3935 Set nz = `PETSC_DEFAULT` and `nnz` = `NULL` for PETSc to control dynamic memory 3936 allocation. 3937 3938 You can call `MatGetInfo()` to get information on how effective the preallocation was; 3939 for example the fields mallocs,nz_allocated,nz_used,nz_unneeded; 3940 You can also run with the option -info and look for messages with the string 3941 malloc in them to see if additional memory allocation was needed. 3942 3943 Developer Notes: 3944 Use nz of `MAT_SKIP_ALLOCATION` to not allocate any space for the matrix 3945 entries or columns indices 3946 3947 By default, this format uses inodes (identical nodes) when possible, to 3948 improve numerical efficiency of matrix-vector products and solves. We 3949 search for consecutive rows with the same nonzero structure, thereby 3950 reusing matrix information to achieve increased efficiency. 3951 3952 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateAIJ()`, `MatSetValues()`, `MatSeqAIJSetColumnIndices()`, `MatCreateSeqAIJWithArrays()`, `MatGetInfo()`, 3953 `MatSeqAIJSetTotalPreallocation()` 3954 @*/ 3955 PetscErrorCode MatSeqAIJSetPreallocation(Mat B, PetscInt nz, const PetscInt nnz[]) 3956 { 3957 PetscFunctionBegin; 3958 PetscValidHeaderSpecific(B, MAT_CLASSID, 1); 3959 PetscValidType(B, 1); 3960 PetscTryMethod(B, "MatSeqAIJSetPreallocation_C", (Mat, PetscInt, const PetscInt[]), (B, nz, nnz)); 3961 PetscFunctionReturn(PETSC_SUCCESS); 3962 } 3963 3964 PetscErrorCode MatSeqAIJSetPreallocation_SeqAIJ(Mat B, PetscInt nz, const PetscInt *nnz) 3965 { 3966 Mat_SeqAIJ *b = (Mat_SeqAIJ *)B->data; 3967 PetscBool skipallocation = PETSC_FALSE, realalloc = PETSC_FALSE; 3968 PetscInt i; 3969 3970 PetscFunctionBegin; 3971 if (B->hash_active) { 3972 B->ops[0] = b->cops; 3973 PetscCall(PetscHMapIJVDestroy(&b->ht)); 3974 PetscCall(PetscFree(b->dnz)); 3975 B->hash_active = PETSC_FALSE; 3976 } 3977 if (nz >= 0 || nnz) realalloc = PETSC_TRUE; 3978 if (nz == MAT_SKIP_ALLOCATION) { 3979 skipallocation = PETSC_TRUE; 3980 nz = 0; 3981 } 3982 PetscCall(PetscLayoutSetUp(B->rmap)); 3983 PetscCall(PetscLayoutSetUp(B->cmap)); 3984 3985 if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 5; 3986 PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nz cannot be less than 0: value %" PetscInt_FMT, nz); 3987 if (nnz) { 3988 for (i = 0; i < B->rmap->n; i++) { 3989 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]); 3990 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); 3991 } 3992 } 3993 3994 B->preallocated = PETSC_TRUE; 3995 if (!skipallocation) { 3996 if (!b->imax) { PetscCall(PetscMalloc1(B->rmap->n, &b->imax)); } 3997 if (!b->ilen) { 3998 /* b->ilen will count nonzeros in each row so far. */ 3999 PetscCall(PetscCalloc1(B->rmap->n, &b->ilen)); 4000 } else { 4001 PetscCall(PetscMemzero(b->ilen, B->rmap->n * sizeof(PetscInt))); 4002 } 4003 if (!b->ipre) PetscCall(PetscMalloc1(B->rmap->n, &b->ipre)); 4004 if (!nnz) { 4005 if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 10; 4006 else if (nz < 0) nz = 1; 4007 nz = PetscMin(nz, B->cmap->n); 4008 for (i = 0; i < B->rmap->n; i++) b->imax[i] = nz; 4009 PetscCall(PetscIntMultError(nz, B->rmap->n, &nz)); 4010 } else { 4011 PetscInt64 nz64 = 0; 4012 for (i = 0; i < B->rmap->n; i++) { 4013 b->imax[i] = nnz[i]; 4014 nz64 += nnz[i]; 4015 } 4016 PetscCall(PetscIntCast(nz64, &nz)); 4017 } 4018 4019 /* allocate the matrix space */ 4020 PetscCall(MatSeqXAIJFreeAIJ(B, &b->a, &b->j, &b->i)); 4021 PetscCall(PetscShmgetAllocateArray(nz, sizeof(PetscInt), (void **)&b->j)); 4022 PetscCall(PetscShmgetAllocateArray(B->rmap->n + 1, sizeof(PetscInt), (void **)&b->i)); 4023 b->free_ij = PETSC_TRUE; 4024 if (B->structure_only) { 4025 b->free_a = PETSC_FALSE; 4026 } else { 4027 PetscCall(PetscShmgetAllocateArray(nz, sizeof(PetscScalar), (void **)&b->a)); 4028 b->free_a = PETSC_TRUE; 4029 } 4030 b->i[0] = 0; 4031 for (i = 1; i < B->rmap->n + 1; i++) b->i[i] = b->i[i - 1] + b->imax[i - 1]; 4032 } else { 4033 b->free_a = PETSC_FALSE; 4034 b->free_ij = PETSC_FALSE; 4035 } 4036 4037 if (b->ipre && nnz != b->ipre && b->imax) { 4038 /* reserve user-requested sparsity */ 4039 PetscCall(PetscArraycpy(b->ipre, b->imax, B->rmap->n)); 4040 } 4041 4042 b->nz = 0; 4043 b->maxnz = nz; 4044 B->info.nz_unneeded = (double)b->maxnz; 4045 if (realalloc) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 4046 B->was_assembled = PETSC_FALSE; 4047 B->assembled = PETSC_FALSE; 4048 /* We simply deem preallocation has changed nonzero state. Updating the state 4049 will give clients (like AIJKokkos) a chance to know something has happened. 4050 */ 4051 B->nonzerostate++; 4052 PetscFunctionReturn(PETSC_SUCCESS); 4053 } 4054 4055 static PetscErrorCode MatResetPreallocation_SeqAIJ(Mat A) 4056 { 4057 Mat_SeqAIJ *a; 4058 PetscInt i; 4059 PetscBool skipreset; 4060 4061 PetscFunctionBegin; 4062 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 4063 4064 /* Check local size. If zero, then return */ 4065 if (!A->rmap->n) PetscFunctionReturn(PETSC_SUCCESS); 4066 4067 a = (Mat_SeqAIJ *)A->data; 4068 /* if no saved info, we error out */ 4069 PetscCheck(a->ipre, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "No saved preallocation info "); 4070 4071 PetscCheck(a->i && a->imax && a->ilen, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Memory info is incomplete, and can not reset preallocation "); 4072 4073 PetscCall(PetscArraycmp(a->ipre, a->ilen, A->rmap->n, &skipreset)); 4074 if (!skipreset) { 4075 PetscCall(PetscArraycpy(a->imax, a->ipre, A->rmap->n)); 4076 PetscCall(PetscArrayzero(a->ilen, A->rmap->n)); 4077 a->i[0] = 0; 4078 for (i = 1; i < A->rmap->n + 1; i++) a->i[i] = a->i[i - 1] + a->imax[i - 1]; 4079 A->preallocated = PETSC_TRUE; 4080 a->nz = 0; 4081 a->maxnz = a->i[A->rmap->n]; 4082 A->info.nz_unneeded = (double)a->maxnz; 4083 A->was_assembled = PETSC_FALSE; 4084 A->assembled = PETSC_FALSE; 4085 } 4086 PetscFunctionReturn(PETSC_SUCCESS); 4087 } 4088 4089 /*@ 4090 MatSeqAIJSetPreallocationCSR - Allocates memory for a sparse sequential matrix in `MATSEQAIJ` format. 4091 4092 Input Parameters: 4093 + B - the matrix 4094 . i - the indices into `j` for the start of each row (indices start with zero) 4095 . j - the column indices for each row (indices start with zero) these must be sorted for each row 4096 - v - optional values in the matrix, use `NULL` if not provided 4097 4098 Level: developer 4099 4100 Notes: 4101 The `i`,`j`,`v` values are COPIED with this routine; to avoid the copy use `MatCreateSeqAIJWithArrays()` 4102 4103 This routine may be called multiple times with different nonzero patterns (or the same nonzero pattern). The nonzero 4104 structure will be the union of all the previous nonzero structures. 4105 4106 Developer Notes: 4107 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 4108 then just copies the `v` values directly with `PetscMemcpy()`. 4109 4110 This routine could also take a `PetscCopyMode` argument to allow sharing the values instead of always copying them. 4111 4112 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateSeqAIJ()`, `MatSetValues()`, `MatSeqAIJSetPreallocation()`, `MATSEQAIJ`, `MatResetPreallocation()` 4113 @*/ 4114 PetscErrorCode MatSeqAIJSetPreallocationCSR(Mat B, const PetscInt i[], const PetscInt j[], const PetscScalar v[]) 4115 { 4116 PetscFunctionBegin; 4117 PetscValidHeaderSpecific(B, MAT_CLASSID, 1); 4118 PetscValidType(B, 1); 4119 PetscTryMethod(B, "MatSeqAIJSetPreallocationCSR_C", (Mat, const PetscInt[], const PetscInt[], const PetscScalar[]), (B, i, j, v)); 4120 PetscFunctionReturn(PETSC_SUCCESS); 4121 } 4122 4123 static PetscErrorCode MatSeqAIJSetPreallocationCSR_SeqAIJ(Mat B, const PetscInt Ii[], const PetscInt J[], const PetscScalar v[]) 4124 { 4125 PetscInt i; 4126 PetscInt m, n; 4127 PetscInt nz; 4128 PetscInt *nnz; 4129 4130 PetscFunctionBegin; 4131 PetscCheck(Ii[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Ii[0] must be 0 it is %" PetscInt_FMT, Ii[0]); 4132 4133 PetscCall(PetscLayoutSetUp(B->rmap)); 4134 PetscCall(PetscLayoutSetUp(B->cmap)); 4135 4136 PetscCall(MatGetSize(B, &m, &n)); 4137 PetscCall(PetscMalloc1(m + 1, &nnz)); 4138 for (i = 0; i < m; i++) { 4139 nz = Ii[i + 1] - Ii[i]; 4140 PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local row %" PetscInt_FMT " has a negative number of columns %" PetscInt_FMT, i, nz); 4141 nnz[i] = nz; 4142 } 4143 PetscCall(MatSeqAIJSetPreallocation(B, 0, nnz)); 4144 PetscCall(PetscFree(nnz)); 4145 4146 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)); 4147 4148 PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY)); 4149 PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY)); 4150 4151 PetscCall(MatSetOption(B, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE)); 4152 PetscFunctionReturn(PETSC_SUCCESS); 4153 } 4154 4155 /*@ 4156 MatSeqAIJKron - Computes `C`, the Kronecker product of `A` and `B`. 4157 4158 Input Parameters: 4159 + A - left-hand side matrix 4160 . B - right-hand side matrix 4161 - reuse - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX` 4162 4163 Output Parameter: 4164 . C - Kronecker product of `A` and `B` 4165 4166 Level: intermediate 4167 4168 Note: 4169 `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the product matrix has not changed from that last call to `MatSeqAIJKron()`. 4170 4171 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MATKAIJ`, `MatReuse` 4172 @*/ 4173 PetscErrorCode MatSeqAIJKron(Mat A, Mat B, MatReuse reuse, Mat *C) 4174 { 4175 PetscFunctionBegin; 4176 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 4177 PetscValidType(A, 1); 4178 PetscValidHeaderSpecific(B, MAT_CLASSID, 2); 4179 PetscValidType(B, 2); 4180 PetscAssertPointer(C, 4); 4181 if (reuse == MAT_REUSE_MATRIX) { 4182 PetscValidHeaderSpecific(*C, MAT_CLASSID, 4); 4183 PetscValidType(*C, 4); 4184 } 4185 PetscTryMethod(A, "MatSeqAIJKron_C", (Mat, Mat, MatReuse, Mat *), (A, B, reuse, C)); 4186 PetscFunctionReturn(PETSC_SUCCESS); 4187 } 4188 4189 static PetscErrorCode MatSeqAIJKron_SeqAIJ(Mat A, Mat B, MatReuse reuse, Mat *C) 4190 { 4191 Mat newmat; 4192 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 4193 Mat_SeqAIJ *b = (Mat_SeqAIJ *)B->data; 4194 PetscScalar *v; 4195 const PetscScalar *aa, *ba; 4196 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; 4197 PetscBool flg; 4198 4199 PetscFunctionBegin; 4200 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 4201 PetscCheck(A->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 4202 PetscCheck(!B->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 4203 PetscCheck(B->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 4204 PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &flg)); 4205 PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatType %s", ((PetscObject)B)->type_name); 4206 PetscCheck(reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatReuse %d", (int)reuse); 4207 if (reuse == MAT_INITIAL_MATRIX) { 4208 PetscCall(PetscMalloc2(am * bm + 1, &i, a->i[am] * b->i[bm], &j)); 4209 PetscCall(MatCreate(PETSC_COMM_SELF, &newmat)); 4210 PetscCall(MatSetSizes(newmat, am * bm, an * bn, am * bm, an * bn)); 4211 PetscCall(MatSetType(newmat, MATAIJ)); 4212 i[0] = 0; 4213 for (m = 0; m < am; ++m) { 4214 for (p = 0; p < bm; ++p) { 4215 i[m * bm + p + 1] = i[m * bm + p] + (a->i[m + 1] - a->i[m]) * (b->i[p + 1] - b->i[p]); 4216 for (n = a->i[m]; n < a->i[m + 1]; ++n) { 4217 for (q = b->i[p]; q < b->i[p + 1]; ++q) j[nnz++] = a->j[n] * bn + b->j[q]; 4218 } 4219 } 4220 } 4221 PetscCall(MatSeqAIJSetPreallocationCSR(newmat, i, j, NULL)); 4222 *C = newmat; 4223 PetscCall(PetscFree2(i, j)); 4224 nnz = 0; 4225 } 4226 PetscCall(MatSeqAIJGetArray(*C, &v)); 4227 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 4228 PetscCall(MatSeqAIJGetArrayRead(B, &ba)); 4229 for (m = 0; m < am; ++m) { 4230 for (p = 0; p < bm; ++p) { 4231 for (n = a->i[m]; n < a->i[m + 1]; ++n) { 4232 for (q = b->i[p]; q < b->i[p + 1]; ++q) v[nnz++] = aa[n] * ba[q]; 4233 } 4234 } 4235 } 4236 PetscCall(MatSeqAIJRestoreArray(*C, &v)); 4237 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 4238 PetscCall(MatSeqAIJRestoreArrayRead(B, &ba)); 4239 PetscFunctionReturn(PETSC_SUCCESS); 4240 } 4241 4242 #include <../src/mat/impls/dense/seq/dense.h> 4243 #include <petsc/private/kernels/petscaxpy.h> 4244 4245 /* 4246 Computes (B'*A')' since computing B*A directly is untenable 4247 4248 n p p 4249 [ ] [ ] [ ] 4250 m [ A ] * n [ B ] = m [ C ] 4251 [ ] [ ] [ ] 4252 4253 */ 4254 PetscErrorCode MatMatMultNumeric_SeqDense_SeqAIJ(Mat A, Mat B, Mat C) 4255 { 4256 Mat_SeqDense *sub_a = (Mat_SeqDense *)A->data; 4257 Mat_SeqAIJ *sub_b = (Mat_SeqAIJ *)B->data; 4258 Mat_SeqDense *sub_c = (Mat_SeqDense *)C->data; 4259 PetscInt i, j, n, m, q, p; 4260 const PetscInt *ii, *idx; 4261 const PetscScalar *b, *a, *a_q; 4262 PetscScalar *c, *c_q; 4263 PetscInt clda = sub_c->lda; 4264 PetscInt alda = sub_a->lda; 4265 4266 PetscFunctionBegin; 4267 m = A->rmap->n; 4268 n = A->cmap->n; 4269 p = B->cmap->n; 4270 a = sub_a->v; 4271 b = sub_b->a; 4272 c = sub_c->v; 4273 if (clda == m) { 4274 PetscCall(PetscArrayzero(c, m * p)); 4275 } else { 4276 for (j = 0; j < p; j++) 4277 for (i = 0; i < m; i++) c[j * clda + i] = 0.0; 4278 } 4279 ii = sub_b->i; 4280 idx = sub_b->j; 4281 for (i = 0; i < n; i++) { 4282 q = ii[i + 1] - ii[i]; 4283 while (q-- > 0) { 4284 c_q = c + clda * (*idx); 4285 a_q = a + alda * i; 4286 PetscKernelAXPY(c_q, *b, a_q, m); 4287 idx++; 4288 b++; 4289 } 4290 } 4291 PetscFunctionReturn(PETSC_SUCCESS); 4292 } 4293 4294 PetscErrorCode MatMatMultSymbolic_SeqDense_SeqAIJ(Mat A, Mat B, PetscReal fill, Mat C) 4295 { 4296 PetscInt m = A->rmap->n, n = B->cmap->n; 4297 PetscBool cisdense; 4298 4299 PetscFunctionBegin; 4300 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); 4301 PetscCall(MatSetSizes(C, m, n, m, n)); 4302 PetscCall(MatSetBlockSizesFromMats(C, A, B)); 4303 PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATSEQDENSECUDA, MATSEQDENSEHIP, "")); 4304 if (!cisdense) PetscCall(MatSetType(C, MATDENSE)); 4305 PetscCall(MatSetUp(C)); 4306 4307 C->ops->matmultnumeric = MatMatMultNumeric_SeqDense_SeqAIJ; 4308 PetscFunctionReturn(PETSC_SUCCESS); 4309 } 4310 4311 /*MC 4312 MATSEQAIJ - MATSEQAIJ = "seqaij" - A matrix type to be used for sequential sparse matrices, 4313 based on compressed sparse row format. 4314 4315 Options Database Key: 4316 . -mat_type seqaij - sets the matrix type to "seqaij" during a call to MatSetFromOptions() 4317 4318 Level: beginner 4319 4320 Notes: 4321 `MatSetValues()` may be called for this matrix type with a `NULL` argument for the numerical values, 4322 in this case the values associated with the rows and columns one passes in are set to zero 4323 in the matrix 4324 4325 `MatSetOptions`(,`MAT_STRUCTURE_ONLY`,`PETSC_TRUE`) may be called for this matrix type. In this no 4326 space is allocated for the nonzero entries and any entries passed with `MatSetValues()` are ignored 4327 4328 Developer Note: 4329 It would be nice if all matrix formats supported passing `NULL` in for the numerical values 4330 4331 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MatSetFromOptions()`, `MatSetType()`, `MatCreate()`, `MatType`, `MATSELL`, `MATSEQSELL`, `MATMPISELL` 4332 M*/ 4333 4334 /*MC 4335 MATAIJ - MATAIJ = "aij" - A matrix type to be used for sparse matrices. 4336 4337 This matrix type is identical to `MATSEQAIJ` when constructed with a single process communicator, 4338 and `MATMPIAIJ` otherwise. As a result, for single process communicators, 4339 `MatSeqAIJSetPreallocation()` is supported, and similarly `MatMPIAIJSetPreallocation()` is supported 4340 for communicators controlling multiple processes. It is recommended that you call both of 4341 the above preallocation routines for simplicity. 4342 4343 Options Database Key: 4344 . -mat_type aij - sets the matrix type to "aij" during a call to `MatSetFromOptions()` 4345 4346 Level: beginner 4347 4348 Note: 4349 Subclasses include `MATAIJCUSPARSE`, `MATAIJPERM`, `MATAIJSELL`, `MATAIJMKL`, `MATAIJCRL`, and also automatically switches over to use inodes when 4350 enough exist. 4351 4352 .seealso: [](ch_matrices), `Mat`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MATMPIAIJ`, `MATSELL`, `MATSEQSELL`, `MATMPISELL` 4353 M*/ 4354 4355 /*MC 4356 MATAIJCRL - MATAIJCRL = "aijcrl" - A matrix type to be used for sparse matrices. 4357 4358 Options Database Key: 4359 . -mat_type aijcrl - sets the matrix type to "aijcrl" during a call to `MatSetFromOptions()` 4360 4361 Level: beginner 4362 4363 Note: 4364 This matrix type is identical to `MATSEQAIJCRL` when constructed with a single process communicator, 4365 and `MATMPIAIJCRL` otherwise. As a result, for single process communicators, 4366 `MatSeqAIJSetPreallocation()` is supported, and similarly `MatMPIAIJSetPreallocation()` is supported 4367 for communicators controlling multiple processes. It is recommended that you call both of 4368 the above preallocation routines for simplicity. 4369 4370 .seealso: [](ch_matrices), `Mat`, `MatCreateMPIAIJCRL`, `MATSEQAIJCRL`, `MATMPIAIJCRL`, `MATSEQAIJCRL`, `MATMPIAIJCRL` 4371 M*/ 4372 4373 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJCRL(Mat, MatType, MatReuse, Mat *); 4374 #if defined(PETSC_HAVE_ELEMENTAL) 4375 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_Elemental(Mat, MatType, MatReuse, Mat *); 4376 #endif 4377 #if defined(PETSC_HAVE_SCALAPACK) 4378 PETSC_INTERN PetscErrorCode MatConvert_AIJ_ScaLAPACK(Mat, MatType, MatReuse, Mat *); 4379 #endif 4380 #if defined(PETSC_HAVE_HYPRE) 4381 PETSC_INTERN PetscErrorCode MatConvert_AIJ_HYPRE(Mat A, MatType, MatReuse, Mat *); 4382 #endif 4383 4384 PETSC_EXTERN PetscErrorCode MatConvert_SeqAIJ_SeqSELL(Mat, MatType, MatReuse, Mat *); 4385 PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat, MatType, MatReuse, Mat *); 4386 PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat); 4387 4388 /*@C 4389 MatSeqAIJGetArray - gives read/write access to the array where the data for a `MATSEQAIJ` matrix is stored 4390 4391 Not Collective 4392 4393 Input Parameter: 4394 . A - a `MATSEQAIJ` matrix 4395 4396 Output Parameter: 4397 . array - pointer to the data 4398 4399 Level: intermediate 4400 4401 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJRestoreArray()` 4402 @*/ 4403 PetscErrorCode MatSeqAIJGetArray(Mat A, PetscScalar *array[]) 4404 { 4405 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4406 4407 PetscFunctionBegin; 4408 if (aij->ops->getarray) { 4409 PetscCall((*aij->ops->getarray)(A, array)); 4410 } else { 4411 *array = aij->a; 4412 } 4413 PetscFunctionReturn(PETSC_SUCCESS); 4414 } 4415 4416 /*@C 4417 MatSeqAIJRestoreArray - returns access to the array where the data for a `MATSEQAIJ` matrix is stored obtained by `MatSeqAIJGetArray()` 4418 4419 Not Collective 4420 4421 Input Parameters: 4422 + A - a `MATSEQAIJ` matrix 4423 - array - pointer to the data 4424 4425 Level: intermediate 4426 4427 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()` 4428 @*/ 4429 PetscErrorCode MatSeqAIJRestoreArray(Mat A, PetscScalar *array[]) 4430 { 4431 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4432 4433 PetscFunctionBegin; 4434 if (aij->ops->restorearray) { 4435 PetscCall((*aij->ops->restorearray)(A, array)); 4436 } else { 4437 *array = NULL; 4438 } 4439 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 4440 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 4441 PetscFunctionReturn(PETSC_SUCCESS); 4442 } 4443 4444 /*@C 4445 MatSeqAIJGetArrayRead - gives read-only access to the array where the data for a `MATSEQAIJ` matrix is stored 4446 4447 Not Collective; No Fortran Support 4448 4449 Input Parameter: 4450 . A - a `MATSEQAIJ` matrix 4451 4452 Output Parameter: 4453 . array - pointer to the data 4454 4455 Level: intermediate 4456 4457 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayRead()` 4458 @*/ 4459 PetscErrorCode MatSeqAIJGetArrayRead(Mat A, const PetscScalar *array[]) 4460 { 4461 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4462 4463 PetscFunctionBegin; 4464 if (aij->ops->getarrayread) { 4465 PetscCall((*aij->ops->getarrayread)(A, array)); 4466 } else { 4467 *array = aij->a; 4468 } 4469 PetscFunctionReturn(PETSC_SUCCESS); 4470 } 4471 4472 /*@C 4473 MatSeqAIJRestoreArrayRead - restore the read-only access array obtained from `MatSeqAIJGetArrayRead()` 4474 4475 Not Collective; No Fortran Support 4476 4477 Input Parameter: 4478 . A - a `MATSEQAIJ` matrix 4479 4480 Output Parameter: 4481 . array - pointer to the data 4482 4483 Level: intermediate 4484 4485 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4486 @*/ 4487 PetscErrorCode MatSeqAIJRestoreArrayRead(Mat A, const PetscScalar *array[]) 4488 { 4489 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4490 4491 PetscFunctionBegin; 4492 if (aij->ops->restorearrayread) { 4493 PetscCall((*aij->ops->restorearrayread)(A, array)); 4494 } else { 4495 *array = NULL; 4496 } 4497 PetscFunctionReturn(PETSC_SUCCESS); 4498 } 4499 4500 /*@C 4501 MatSeqAIJGetArrayWrite - gives write-only access to the array where the data for a `MATSEQAIJ` matrix is stored 4502 4503 Not Collective; No Fortran Support 4504 4505 Input Parameter: 4506 . A - a `MATSEQAIJ` matrix 4507 4508 Output Parameter: 4509 . array - pointer to the data 4510 4511 Level: intermediate 4512 4513 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayRead()` 4514 @*/ 4515 PetscErrorCode MatSeqAIJGetArrayWrite(Mat A, PetscScalar *array[]) 4516 { 4517 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4518 4519 PetscFunctionBegin; 4520 if (aij->ops->getarraywrite) { 4521 PetscCall((*aij->ops->getarraywrite)(A, array)); 4522 } else { 4523 *array = aij->a; 4524 } 4525 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 4526 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 4527 PetscFunctionReturn(PETSC_SUCCESS); 4528 } 4529 4530 /*@C 4531 MatSeqAIJRestoreArrayWrite - restore the read-only access array obtained from MatSeqAIJGetArrayRead 4532 4533 Not Collective; No Fortran Support 4534 4535 Input Parameter: 4536 . A - a MATSEQAIJ matrix 4537 4538 Output Parameter: 4539 . array - pointer to the data 4540 4541 Level: intermediate 4542 4543 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4544 @*/ 4545 PetscErrorCode MatSeqAIJRestoreArrayWrite(Mat A, PetscScalar *array[]) 4546 { 4547 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4548 4549 PetscFunctionBegin; 4550 if (aij->ops->restorearraywrite) { 4551 PetscCall((*aij->ops->restorearraywrite)(A, array)); 4552 } else { 4553 *array = NULL; 4554 } 4555 PetscFunctionReturn(PETSC_SUCCESS); 4556 } 4557 4558 /*@C 4559 MatSeqAIJGetCSRAndMemType - Get the CSR arrays and the memory type of the `MATSEQAIJ` matrix 4560 4561 Not Collective; No Fortran Support 4562 4563 Input Parameter: 4564 . mat - a matrix of type `MATSEQAIJ` or its subclasses 4565 4566 Output Parameters: 4567 + i - row map array of the matrix 4568 . j - column index array of the matrix 4569 . a - data array of the matrix 4570 - mtype - memory type of the arrays 4571 4572 Level: developer 4573 4574 Notes: 4575 Any of the output parameters can be `NULL`, in which case the corresponding value is not returned. 4576 If mat is a device matrix, the arrays are on the device. Otherwise, they are on the host. 4577 4578 One can call this routine on a preallocated but not assembled matrix to just get the memory of the CSR underneath the matrix. 4579 If the matrix is assembled, the data array `a` is guaranteed to have the latest values of the matrix. 4580 4581 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4582 @*/ 4583 PetscErrorCode MatSeqAIJGetCSRAndMemType(Mat mat, const PetscInt *i[], const PetscInt *j[], PetscScalar *a[], PetscMemType *mtype) 4584 { 4585 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 4586 4587 PetscFunctionBegin; 4588 PetscCheck(mat->preallocated, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "matrix is not preallocated"); 4589 if (aij->ops->getcsrandmemtype) { 4590 PetscCall((*aij->ops->getcsrandmemtype)(mat, i, j, a, mtype)); 4591 } else { 4592 if (i) *i = aij->i; 4593 if (j) *j = aij->j; 4594 if (a) *a = aij->a; 4595 if (mtype) *mtype = PETSC_MEMTYPE_HOST; 4596 } 4597 PetscFunctionReturn(PETSC_SUCCESS); 4598 } 4599 4600 /*@ 4601 MatSeqAIJGetMaxRowNonzeros - returns the maximum number of nonzeros in any row 4602 4603 Not Collective 4604 4605 Input Parameter: 4606 . A - a `MATSEQAIJ` matrix 4607 4608 Output Parameter: 4609 . nz - the maximum number of nonzeros in any row 4610 4611 Level: intermediate 4612 4613 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJRestoreArray()` 4614 @*/ 4615 PetscErrorCode MatSeqAIJGetMaxRowNonzeros(Mat A, PetscInt *nz) 4616 { 4617 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4618 4619 PetscFunctionBegin; 4620 *nz = aij->rmax; 4621 PetscFunctionReturn(PETSC_SUCCESS); 4622 } 4623 4624 static PetscErrorCode MatCOOStructDestroy_SeqAIJ(void **data) 4625 { 4626 MatCOOStruct_SeqAIJ *coo = (MatCOOStruct_SeqAIJ *)*data; 4627 4628 PetscFunctionBegin; 4629 PetscCall(PetscFree(coo->perm)); 4630 PetscCall(PetscFree(coo->jmap)); 4631 PetscCall(PetscFree(coo)); 4632 PetscFunctionReturn(PETSC_SUCCESS); 4633 } 4634 4635 PetscErrorCode MatSetPreallocationCOO_SeqAIJ(Mat mat, PetscCount coo_n, PetscInt coo_i[], PetscInt coo_j[]) 4636 { 4637 MPI_Comm comm; 4638 PetscInt *i, *j; 4639 PetscInt M, N, row, iprev; 4640 PetscCount k, p, q, nneg, nnz, start, end; /* Index the coo array, so use PetscCount as their type */ 4641 PetscInt *Ai; /* Change to PetscCount once we use it for row pointers */ 4642 PetscInt *Aj; 4643 PetscScalar *Aa; 4644 Mat_SeqAIJ *seqaij = (Mat_SeqAIJ *)mat->data; 4645 MatType rtype; 4646 PetscCount *perm, *jmap; 4647 MatCOOStruct_SeqAIJ *coo; 4648 PetscBool isorted; 4649 PetscBool hypre; 4650 const char *name; 4651 4652 PetscFunctionBegin; 4653 PetscCall(PetscObjectGetComm((PetscObject)mat, &comm)); 4654 PetscCall(MatGetSize(mat, &M, &N)); 4655 i = coo_i; 4656 j = coo_j; 4657 PetscCall(PetscMalloc1(coo_n, &perm)); 4658 4659 /* 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) */ 4660 isorted = PETSC_TRUE; 4661 iprev = PETSC_INT_MIN; 4662 for (k = 0; k < coo_n; k++) { 4663 if (j[k] < 0) i[k] = -1; 4664 if (isorted) { 4665 if (i[k] < iprev) isorted = PETSC_FALSE; 4666 else iprev = i[k]; 4667 } 4668 perm[k] = k; 4669 } 4670 4671 /* Sort by row if not already */ 4672 if (!isorted) PetscCall(PetscSortIntWithIntCountArrayPair(coo_n, i, j, perm)); 4673 4674 /* Advance k to the first row with a non-negative index */ 4675 for (k = 0; k < coo_n; k++) 4676 if (i[k] >= 0) break; 4677 nneg = k; 4678 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 */ 4679 nnz = 0; /* Total number of unique nonzeros to be counted */ 4680 jmap++; /* Inc jmap by 1 for convenience */ 4681 4682 PetscCall(PetscShmgetAllocateArray(M + 1, sizeof(PetscInt), (void **)&Ai)); /* CSR of A */ 4683 PetscCall(PetscArrayzero(Ai, M + 1)); 4684 PetscCall(PetscShmgetAllocateArray(coo_n - nneg, sizeof(PetscInt), (void **)&Aj)); /* We have at most coo_n-nneg unique nonzeros */ 4685 4686 PetscCall(PetscObjectGetName((PetscObject)mat, &name)); 4687 PetscCall(PetscStrcmp("_internal_COO_mat_for_hypre", name, &hypre)); 4688 4689 /* In each row, sort by column, then unique column indices to get row length */ 4690 Ai++; /* Inc by 1 for convenience */ 4691 q = 0; /* q-th unique nonzero, with q starting from 0 */ 4692 while (k < coo_n) { 4693 PetscBool strictly_sorted; // this row is strictly sorted? 4694 PetscInt jprev; 4695 4696 /* get [start,end) indices for this row; also check if cols in this row are strictly sorted */ 4697 row = i[k]; 4698 start = k; 4699 jprev = PETSC_INT_MIN; 4700 strictly_sorted = PETSC_TRUE; 4701 while (k < coo_n && i[k] == row) { 4702 if (strictly_sorted) { 4703 if (j[k] <= jprev) strictly_sorted = PETSC_FALSE; 4704 else jprev = j[k]; 4705 } 4706 k++; 4707 } 4708 end = k; 4709 4710 /* hack for HYPRE: swap min column to diag so that diagonal values will go first */ 4711 if (hypre) { 4712 PetscInt minj = PETSC_INT_MAX; 4713 PetscBool hasdiag = PETSC_FALSE; 4714 4715 if (strictly_sorted) { // fast path to swap the first and the diag 4716 PetscCount tmp; 4717 for (p = start; p < end; p++) { 4718 if (j[p] == row && p != start) { 4719 j[p] = j[start]; // swap j[], so that the diagonal value will go first (manipulated by perm[]) 4720 j[start] = row; 4721 tmp = perm[start]; 4722 perm[start] = perm[p]; // also swap perm[] so we can save the call to PetscSortIntWithCountArray() below 4723 perm[p] = tmp; 4724 break; 4725 } 4726 } 4727 } else { 4728 for (p = start; p < end; p++) { 4729 hasdiag = (PetscBool)(hasdiag || (j[p] == row)); 4730 minj = PetscMin(minj, j[p]); 4731 } 4732 4733 if (hasdiag) { 4734 for (p = start; p < end; p++) { 4735 if (j[p] == minj) j[p] = row; 4736 else if (j[p] == row) j[p] = minj; 4737 } 4738 } 4739 } 4740 } 4741 // sort by columns in a row. perm[] indicates their original order 4742 if (!strictly_sorted) PetscCall(PetscSortIntWithCountArray(end - start, j + start, perm + start)); 4743 4744 if (strictly_sorted) { // fast path to set Aj[], jmap[], Ai[], nnz, q 4745 for (p = start; p < end; p++, q++) { 4746 Aj[q] = j[p]; 4747 jmap[q] = 1; 4748 } 4749 PetscCall(PetscIntCast(end - start, Ai + row)); 4750 nnz += Ai[row]; // q is already advanced 4751 } else { 4752 /* Find number of unique col entries in this row */ 4753 Aj[q] = j[start]; /* Log the first nonzero in this row */ 4754 jmap[q] = 1; /* Number of repeats of this nonzero entry */ 4755 Ai[row] = 1; 4756 nnz++; 4757 4758 for (p = start + 1; p < end; p++) { /* Scan remaining nonzero in this row */ 4759 if (j[p] != j[p - 1]) { /* Meet a new nonzero */ 4760 q++; 4761 jmap[q] = 1; 4762 Aj[q] = j[p]; 4763 Ai[row]++; 4764 nnz++; 4765 } else { 4766 jmap[q]++; 4767 } 4768 } 4769 q++; /* Move to next row and thus next unique nonzero */ 4770 } 4771 } 4772 4773 Ai--; /* Back to the beginning of Ai[] */ 4774 for (k = 0; k < M; k++) Ai[k + 1] += Ai[k]; 4775 jmap--; // Back to the beginning of jmap[] 4776 jmap[0] = 0; 4777 for (k = 0; k < nnz; k++) jmap[k + 1] += jmap[k]; 4778 4779 if (nnz < coo_n - nneg) { /* Reallocate with actual number of unique nonzeros */ 4780 PetscCount *jmap_new; 4781 PetscInt *Aj_new; 4782 4783 PetscCall(PetscMalloc1(nnz + 1, &jmap_new)); 4784 PetscCall(PetscArraycpy(jmap_new, jmap, nnz + 1)); 4785 PetscCall(PetscFree(jmap)); 4786 jmap = jmap_new; 4787 4788 PetscCall(PetscShmgetAllocateArray(nnz, sizeof(PetscInt), (void **)&Aj_new)); 4789 PetscCall(PetscArraycpy(Aj_new, Aj, nnz)); 4790 PetscCall(PetscShmgetDeallocateArray((void **)&Aj)); 4791 Aj = Aj_new; 4792 } 4793 4794 if (nneg) { /* Discard heading entries with negative indices in perm[], as we'll access it from index 0 in MatSetValuesCOO */ 4795 PetscCount *perm_new; 4796 4797 PetscCall(PetscMalloc1(coo_n - nneg, &perm_new)); 4798 PetscCall(PetscArraycpy(perm_new, perm + nneg, coo_n - nneg)); 4799 PetscCall(PetscFree(perm)); 4800 perm = perm_new; 4801 } 4802 4803 PetscCall(MatGetRootType_Private(mat, &rtype)); 4804 PetscCall(PetscShmgetAllocateArray(nnz, sizeof(PetscScalar), (void **)&Aa)); 4805 PetscCall(PetscArrayzero(Aa, nnz)); 4806 PetscCall(MatSetSeqAIJWithArrays_private(PETSC_COMM_SELF, M, N, Ai, Aj, Aa, rtype, mat)); 4807 4808 seqaij->free_a = seqaij->free_ij = PETSC_TRUE; /* Let newmat own Ai, Aj and Aa */ 4809 4810 // Put the COO struct in a container and then attach that to the matrix 4811 PetscCall(PetscMalloc1(1, &coo)); 4812 PetscCall(PetscIntCast(nnz, &coo->nz)); 4813 coo->n = coo_n; 4814 coo->Atot = coo_n - nneg; // Annz is seqaij->nz, so no need to record that again 4815 coo->jmap = jmap; // of length nnz+1 4816 coo->perm = perm; 4817 PetscCall(PetscObjectContainerCompose((PetscObject)mat, "__PETSc_MatCOOStruct_Host", coo, MatCOOStructDestroy_SeqAIJ)); 4818 PetscFunctionReturn(PETSC_SUCCESS); 4819 } 4820 4821 static PetscErrorCode MatSetValuesCOO_SeqAIJ(Mat A, const PetscScalar v[], InsertMode imode) 4822 { 4823 Mat_SeqAIJ *aseq = (Mat_SeqAIJ *)A->data; 4824 PetscCount i, j, Annz = aseq->nz; 4825 PetscCount *perm, *jmap; 4826 PetscScalar *Aa; 4827 PetscContainer container; 4828 MatCOOStruct_SeqAIJ *coo; 4829 4830 PetscFunctionBegin; 4831 PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_MatCOOStruct_Host", (PetscObject *)&container)); 4832 PetscCheck(container, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not found MatCOOStruct on this matrix"); 4833 PetscCall(PetscContainerGetPointer(container, (void **)&coo)); 4834 perm = coo->perm; 4835 jmap = coo->jmap; 4836 PetscCall(MatSeqAIJGetArray(A, &Aa)); 4837 for (i = 0; i < Annz; i++) { 4838 PetscScalar sum = 0.0; 4839 for (j = jmap[i]; j < jmap[i + 1]; j++) sum += v[perm[j]]; 4840 Aa[i] = (imode == INSERT_VALUES ? 0.0 : Aa[i]) + sum; 4841 } 4842 PetscCall(MatSeqAIJRestoreArray(A, &Aa)); 4843 PetscFunctionReturn(PETSC_SUCCESS); 4844 } 4845 4846 #if defined(PETSC_HAVE_CUDA) 4847 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJCUSPARSE(Mat, MatType, MatReuse, Mat *); 4848 #endif 4849 #if defined(PETSC_HAVE_HIP) 4850 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJHIPSPARSE(Mat, MatType, MatReuse, Mat *); 4851 #endif 4852 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 4853 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJKokkos(Mat, MatType, MatReuse, Mat *); 4854 #endif 4855 4856 PETSC_EXTERN PetscErrorCode MatCreate_SeqAIJ(Mat B) 4857 { 4858 Mat_SeqAIJ *b; 4859 PetscMPIInt size; 4860 4861 PetscFunctionBegin; 4862 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)B), &size)); 4863 PetscCheck(size <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Comm must be of size 1"); 4864 4865 PetscCall(PetscNew(&b)); 4866 4867 B->data = (void *)b; 4868 B->ops[0] = MatOps_Values; 4869 if (B->sortedfull) B->ops->setvalues = MatSetValues_SeqAIJ_SortedFull; 4870 4871 b->row = NULL; 4872 b->col = NULL; 4873 b->icol = NULL; 4874 b->reallocs = 0; 4875 b->ignorezeroentries = PETSC_FALSE; 4876 b->roworiented = PETSC_TRUE; 4877 b->nonew = 0; 4878 b->diag = NULL; 4879 b->solve_work = NULL; 4880 B->spptr = NULL; 4881 b->saved_values = NULL; 4882 b->idiag = NULL; 4883 b->mdiag = NULL; 4884 b->ssor_work = NULL; 4885 b->omega = 1.0; 4886 b->fshift = 0.0; 4887 b->idiagvalid = PETSC_FALSE; 4888 b->ibdiagvalid = PETSC_FALSE; 4889 b->keepnonzeropattern = PETSC_FALSE; 4890 4891 PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATSEQAIJ)); 4892 #if defined(PETSC_HAVE_MATLAB) 4893 PetscCall(PetscObjectComposeFunction((PetscObject)B, "PetscMatlabEnginePut_C", MatlabEnginePut_SeqAIJ)); 4894 PetscCall(PetscObjectComposeFunction((PetscObject)B, "PetscMatlabEngineGet_C", MatlabEngineGet_SeqAIJ)); 4895 #endif 4896 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetColumnIndices_C", MatSeqAIJSetColumnIndices_SeqAIJ)); 4897 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatStoreValues_C", MatStoreValues_SeqAIJ)); 4898 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatRetrieveValues_C", MatRetrieveValues_SeqAIJ)); 4899 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqsbaij_C", MatConvert_SeqAIJ_SeqSBAIJ)); 4900 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqbaij_C", MatConvert_SeqAIJ_SeqBAIJ)); 4901 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijperm_C", MatConvert_SeqAIJ_SeqAIJPERM)); 4902 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijsell_C", MatConvert_SeqAIJ_SeqAIJSELL)); 4903 #if defined(PETSC_HAVE_MKL_SPARSE) 4904 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijmkl_C", MatConvert_SeqAIJ_SeqAIJMKL)); 4905 #endif 4906 #if defined(PETSC_HAVE_CUDA) 4907 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijcusparse_C", MatConvert_SeqAIJ_SeqAIJCUSPARSE)); 4908 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaijcusparse_seqaij_C", MatProductSetFromOptions_SeqAIJ)); 4909 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaijcusparse_C", MatProductSetFromOptions_SeqAIJ)); 4910 #endif 4911 #if defined(PETSC_HAVE_HIP) 4912 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijhipsparse_C", MatConvert_SeqAIJ_SeqAIJHIPSPARSE)); 4913 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaijhipsparse_seqaij_C", MatProductSetFromOptions_SeqAIJ)); 4914 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaijhipsparse_C", MatProductSetFromOptions_SeqAIJ)); 4915 #endif 4916 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 4917 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijkokkos_C", MatConvert_SeqAIJ_SeqAIJKokkos)); 4918 #endif 4919 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijcrl_C", MatConvert_SeqAIJ_SeqAIJCRL)); 4920 #if defined(PETSC_HAVE_ELEMENTAL) 4921 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_elemental_C", MatConvert_SeqAIJ_Elemental)); 4922 #endif 4923 #if defined(PETSC_HAVE_SCALAPACK) 4924 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_scalapack_C", MatConvert_AIJ_ScaLAPACK)); 4925 #endif 4926 #if defined(PETSC_HAVE_HYPRE) 4927 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_hypre_C", MatConvert_AIJ_HYPRE)); 4928 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_transpose_seqaij_seqaij_C", MatProductSetFromOptions_Transpose_AIJ_AIJ)); 4929 #endif 4930 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqdense_C", MatConvert_SeqAIJ_SeqDense)); 4931 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqsell_C", MatConvert_SeqAIJ_SeqSELL)); 4932 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_is_C", MatConvert_XAIJ_IS)); 4933 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsTranspose_C", MatIsTranspose_SeqAIJ)); 4934 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsHermitianTranspose_C", MatIsHermitianTranspose_SeqAIJ)); 4935 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetPreallocation_C", MatSeqAIJSetPreallocation_SeqAIJ)); 4936 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatResetPreallocation_C", MatResetPreallocation_SeqAIJ)); 4937 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatResetHash_C", MatResetHash_SeqAIJ)); 4938 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetPreallocationCSR_C", MatSeqAIJSetPreallocationCSR_SeqAIJ)); 4939 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatReorderForNonzeroDiagonal_C", MatReorderForNonzeroDiagonal_SeqAIJ)); 4940 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_is_seqaij_C", MatProductSetFromOptions_IS_XAIJ)); 4941 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqdense_seqaij_C", MatProductSetFromOptions_SeqDense_SeqAIJ)); 4942 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaij_C", MatProductSetFromOptions_SeqAIJ)); 4943 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJKron_C", MatSeqAIJKron_SeqAIJ)); 4944 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_SeqAIJ)); 4945 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSetValuesCOO_C", MatSetValuesCOO_SeqAIJ)); 4946 PetscCall(MatCreate_SeqAIJ_Inode(B)); 4947 PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATSEQAIJ)); 4948 PetscCall(MatSeqAIJSetTypeFromOptions(B)); /* this allows changing the matrix subtype to say MATSEQAIJPERM */ 4949 PetscFunctionReturn(PETSC_SUCCESS); 4950 } 4951 4952 /* 4953 Given a matrix generated with MatGetFactor() duplicates all the information in A into C 4954 */ 4955 PetscErrorCode MatDuplicateNoCreate_SeqAIJ(Mat C, Mat A, MatDuplicateOption cpvalues, PetscBool mallocmatspace) 4956 { 4957 Mat_SeqAIJ *c = (Mat_SeqAIJ *)C->data, *a = (Mat_SeqAIJ *)A->data; 4958 PetscInt m = A->rmap->n, i; 4959 4960 PetscFunctionBegin; 4961 PetscCheck(A->assembled || cpvalues == MAT_DO_NOT_COPY_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot duplicate unassembled matrix"); 4962 4963 C->factortype = A->factortype; 4964 c->row = NULL; 4965 c->col = NULL; 4966 c->icol = NULL; 4967 c->reallocs = 0; 4968 c->diagonaldense = a->diagonaldense; 4969 4970 C->assembled = A->assembled; 4971 4972 if (A->preallocated) { 4973 PetscCall(PetscLayoutReference(A->rmap, &C->rmap)); 4974 PetscCall(PetscLayoutReference(A->cmap, &C->cmap)); 4975 4976 if (!A->hash_active) { 4977 PetscCall(PetscMalloc1(m, &c->imax)); 4978 PetscCall(PetscMemcpy(c->imax, a->imax, m * sizeof(PetscInt))); 4979 PetscCall(PetscMalloc1(m, &c->ilen)); 4980 PetscCall(PetscMemcpy(c->ilen, a->ilen, m * sizeof(PetscInt))); 4981 4982 /* allocate the matrix space */ 4983 if (mallocmatspace) { 4984 PetscCall(PetscShmgetAllocateArray(a->i[m], sizeof(PetscScalar), (void **)&c->a)); 4985 PetscCall(PetscShmgetAllocateArray(a->i[m], sizeof(PetscInt), (void **)&c->j)); 4986 PetscCall(PetscShmgetAllocateArray(m + 1, sizeof(PetscInt), (void **)&c->i)); 4987 PetscCall(PetscArraycpy(c->i, a->i, m + 1)); 4988 c->free_a = PETSC_TRUE; 4989 c->free_ij = PETSC_TRUE; 4990 if (m > 0) { 4991 PetscCall(PetscArraycpy(c->j, a->j, a->i[m])); 4992 if (cpvalues == MAT_COPY_VALUES) { 4993 const PetscScalar *aa; 4994 4995 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 4996 PetscCall(PetscArraycpy(c->a, aa, a->i[m])); 4997 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 4998 } else { 4999 PetscCall(PetscArrayzero(c->a, a->i[m])); 5000 } 5001 } 5002 } 5003 C->preallocated = PETSC_TRUE; 5004 } else { 5005 PetscCheck(mallocmatspace, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Cannot malloc matrix memory from a non-preallocated matrix"); 5006 PetscCall(MatSetUp(C)); 5007 } 5008 5009 c->ignorezeroentries = a->ignorezeroentries; 5010 c->roworiented = a->roworiented; 5011 c->nonew = a->nonew; 5012 if (a->diag) { 5013 PetscCall(PetscMalloc1(m + 1, &c->diag)); 5014 PetscCall(PetscMemcpy(c->diag, a->diag, m * sizeof(PetscInt))); 5015 } else c->diag = NULL; 5016 5017 c->solve_work = NULL; 5018 c->saved_values = NULL; 5019 c->idiag = NULL; 5020 c->ssor_work = NULL; 5021 c->keepnonzeropattern = a->keepnonzeropattern; 5022 5023 c->rmax = a->rmax; 5024 c->nz = a->nz; 5025 c->maxnz = a->nz; /* Since we allocate exactly the right amount */ 5026 5027 c->compressedrow.use = a->compressedrow.use; 5028 c->compressedrow.nrows = a->compressedrow.nrows; 5029 if (a->compressedrow.use) { 5030 i = a->compressedrow.nrows; 5031 PetscCall(PetscMalloc2(i + 1, &c->compressedrow.i, i, &c->compressedrow.rindex)); 5032 PetscCall(PetscArraycpy(c->compressedrow.i, a->compressedrow.i, i + 1)); 5033 PetscCall(PetscArraycpy(c->compressedrow.rindex, a->compressedrow.rindex, i)); 5034 } else { 5035 c->compressedrow.use = PETSC_FALSE; 5036 c->compressedrow.i = NULL; 5037 c->compressedrow.rindex = NULL; 5038 } 5039 c->nonzerorowcnt = a->nonzerorowcnt; 5040 C->nonzerostate = A->nonzerostate; 5041 5042 PetscCall(MatDuplicate_SeqAIJ_Inode(A, cpvalues, &C)); 5043 } 5044 PetscCall(PetscFunctionListDuplicate(((PetscObject)A)->qlist, &((PetscObject)C)->qlist)); 5045 PetscFunctionReturn(PETSC_SUCCESS); 5046 } 5047 5048 PetscErrorCode MatDuplicate_SeqAIJ(Mat A, MatDuplicateOption cpvalues, Mat *B) 5049 { 5050 PetscFunctionBegin; 5051 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B)); 5052 PetscCall(MatSetSizes(*B, A->rmap->n, A->cmap->n, A->rmap->n, A->cmap->n)); 5053 if (!(A->rmap->n % A->rmap->bs) && !(A->cmap->n % A->cmap->bs)) PetscCall(MatSetBlockSizesFromMats(*B, A, A)); 5054 PetscCall(MatSetType(*B, ((PetscObject)A)->type_name)); 5055 PetscCall(MatDuplicateNoCreate_SeqAIJ(*B, A, cpvalues, PETSC_TRUE)); 5056 PetscFunctionReturn(PETSC_SUCCESS); 5057 } 5058 5059 PetscErrorCode MatLoad_SeqAIJ(Mat newMat, PetscViewer viewer) 5060 { 5061 PetscBool isbinary, ishdf5; 5062 5063 PetscFunctionBegin; 5064 PetscValidHeaderSpecific(newMat, MAT_CLASSID, 1); 5065 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 5066 /* force binary viewer to load .info file if it has not yet done so */ 5067 PetscCall(PetscViewerSetUp(viewer)); 5068 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 5069 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 5070 if (isbinary) { 5071 PetscCall(MatLoad_SeqAIJ_Binary(newMat, viewer)); 5072 } else if (ishdf5) { 5073 #if defined(PETSC_HAVE_HDF5) 5074 PetscCall(MatLoad_AIJ_HDF5(newMat, viewer)); 5075 #else 5076 SETERRQ(PetscObjectComm((PetscObject)newMat), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 5077 #endif 5078 } else { 5079 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); 5080 } 5081 PetscFunctionReturn(PETSC_SUCCESS); 5082 } 5083 5084 PetscErrorCode MatLoad_SeqAIJ_Binary(Mat mat, PetscViewer viewer) 5085 { 5086 Mat_SeqAIJ *a = (Mat_SeqAIJ *)mat->data; 5087 PetscInt header[4], *rowlens, M, N, nz, sum, rows, cols, i; 5088 5089 PetscFunctionBegin; 5090 PetscCall(PetscViewerSetUp(viewer)); 5091 5092 /* read in matrix header */ 5093 PetscCall(PetscViewerBinaryRead(viewer, header, 4, NULL, PETSC_INT)); 5094 PetscCheck(header[0] == MAT_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a matrix object in file"); 5095 M = header[1]; 5096 N = header[2]; 5097 nz = header[3]; 5098 PetscCheck(M >= 0, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Matrix row size (%" PetscInt_FMT ") in file is negative", M); 5099 PetscCheck(N >= 0, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Matrix column size (%" PetscInt_FMT ") in file is negative", N); 5100 PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Matrix stored in special format on disk, cannot load as SeqAIJ"); 5101 5102 /* set block sizes from the viewer's .info file */ 5103 PetscCall(MatLoad_Binary_BlockSizes(mat, viewer)); 5104 /* set local and global sizes if not set already */ 5105 if (mat->rmap->n < 0) mat->rmap->n = M; 5106 if (mat->cmap->n < 0) mat->cmap->n = N; 5107 if (mat->rmap->N < 0) mat->rmap->N = M; 5108 if (mat->cmap->N < 0) mat->cmap->N = N; 5109 PetscCall(PetscLayoutSetUp(mat->rmap)); 5110 PetscCall(PetscLayoutSetUp(mat->cmap)); 5111 5112 /* check if the matrix sizes are correct */ 5113 PetscCall(MatGetSize(mat, &rows, &cols)); 5114 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); 5115 5116 /* read in row lengths */ 5117 PetscCall(PetscMalloc1(M, &rowlens)); 5118 PetscCall(PetscViewerBinaryRead(viewer, rowlens, M, NULL, PETSC_INT)); 5119 /* check if sum(rowlens) is same as nz */ 5120 sum = 0; 5121 for (i = 0; i < M; i++) sum += rowlens[i]; 5122 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); 5123 /* preallocate and check sizes */ 5124 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(mat, 0, rowlens)); 5125 PetscCall(MatGetSize(mat, &rows, &cols)); 5126 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); 5127 /* store row lengths */ 5128 PetscCall(PetscArraycpy(a->ilen, rowlens, M)); 5129 PetscCall(PetscFree(rowlens)); 5130 5131 /* fill in "i" row pointers */ 5132 a->i[0] = 0; 5133 for (i = 0; i < M; i++) a->i[i + 1] = a->i[i] + a->ilen[i]; 5134 /* read in "j" column indices */ 5135 PetscCall(PetscViewerBinaryRead(viewer, a->j, nz, NULL, PETSC_INT)); 5136 /* read in "a" nonzero values */ 5137 PetscCall(PetscViewerBinaryRead(viewer, a->a, nz, NULL, PETSC_SCALAR)); 5138 5139 PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY)); 5140 PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY)); 5141 PetscFunctionReturn(PETSC_SUCCESS); 5142 } 5143 5144 PetscErrorCode MatEqual_SeqAIJ(Mat A, Mat B, PetscBool *flg) 5145 { 5146 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *b = (Mat_SeqAIJ *)B->data; 5147 const PetscScalar *aa, *ba; 5148 #if defined(PETSC_USE_COMPLEX) 5149 PetscInt k; 5150 #endif 5151 5152 PetscFunctionBegin; 5153 /* If the matrix dimensions are not equal,or no of nonzeros */ 5154 if ((A->rmap->n != B->rmap->n) || (A->cmap->n != B->cmap->n) || (a->nz != b->nz)) { 5155 *flg = PETSC_FALSE; 5156 PetscFunctionReturn(PETSC_SUCCESS); 5157 } 5158 5159 /* if the a->i are the same */ 5160 PetscCall(PetscArraycmp(a->i, b->i, A->rmap->n + 1, flg)); 5161 if (!*flg) PetscFunctionReturn(PETSC_SUCCESS); 5162 5163 /* if a->j are the same */ 5164 PetscCall(PetscArraycmp(a->j, b->j, a->nz, flg)); 5165 if (!*flg) PetscFunctionReturn(PETSC_SUCCESS); 5166 5167 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 5168 PetscCall(MatSeqAIJGetArrayRead(B, &ba)); 5169 /* if a->a are the same */ 5170 #if defined(PETSC_USE_COMPLEX) 5171 for (k = 0; k < a->nz; k++) { 5172 if (PetscRealPart(aa[k]) != PetscRealPart(ba[k]) || PetscImaginaryPart(aa[k]) != PetscImaginaryPart(ba[k])) { 5173 *flg = PETSC_FALSE; 5174 PetscFunctionReturn(PETSC_SUCCESS); 5175 } 5176 } 5177 #else 5178 PetscCall(PetscArraycmp(aa, ba, a->nz, flg)); 5179 #endif 5180 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 5181 PetscCall(MatSeqAIJRestoreArrayRead(B, &ba)); 5182 PetscFunctionReturn(PETSC_SUCCESS); 5183 } 5184 5185 /*@ 5186 MatCreateSeqAIJWithArrays - Creates an sequential `MATSEQAIJ` matrix using matrix elements (in CSR format) 5187 provided by the user. 5188 5189 Collective 5190 5191 Input Parameters: 5192 + comm - must be an MPI communicator of size 1 5193 . m - number of rows 5194 . n - number of columns 5195 . i - row indices; that is i[0] = 0, i[row] = i[row-1] + number of elements in that row of the matrix 5196 . j - column indices 5197 - a - matrix values 5198 5199 Output Parameter: 5200 . mat - the matrix 5201 5202 Level: intermediate 5203 5204 Notes: 5205 The `i`, `j`, and `a` arrays are not copied by this routine, the user must free these arrays 5206 once the matrix is destroyed and not before 5207 5208 You cannot set new nonzero locations into this matrix, that will generate an error. 5209 5210 The `i` and `j` indices are 0 based 5211 5212 The format which is used for the sparse matrix input, is equivalent to a 5213 row-major ordering.. i.e for the following matrix, the input data expected is 5214 as shown 5215 .vb 5216 1 0 0 5217 2 0 3 5218 4 5 6 5219 5220 i = {0,1,3,6} [size = nrow+1 = 3+1] 5221 j = {0,0,2,0,1,2} [size = 6]; values must be sorted for each row 5222 v = {1,2,3,4,5,6} [size = 6] 5223 .ve 5224 5225 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MatCreateMPIAIJWithArrays()`, `MatMPIAIJSetPreallocationCSR()` 5226 @*/ 5227 PetscErrorCode MatCreateSeqAIJWithArrays(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt i[], PetscInt j[], PetscScalar a[], Mat *mat) 5228 { 5229 PetscInt ii; 5230 Mat_SeqAIJ *aij; 5231 PetscInt jj; 5232 5233 PetscFunctionBegin; 5234 PetscCheck(m <= 0 || i[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "i (row indices) must start with 0"); 5235 PetscCall(MatCreate(comm, mat)); 5236 PetscCall(MatSetSizes(*mat, m, n, m, n)); 5237 /* PetscCall(MatSetBlockSizes(*mat,,)); */ 5238 PetscCall(MatSetType(*mat, MATSEQAIJ)); 5239 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*mat, MAT_SKIP_ALLOCATION, NULL)); 5240 aij = (Mat_SeqAIJ *)(*mat)->data; 5241 PetscCall(PetscMalloc1(m, &aij->imax)); 5242 PetscCall(PetscMalloc1(m, &aij->ilen)); 5243 5244 aij->i = i; 5245 aij->j = j; 5246 aij->a = a; 5247 aij->nonew = -1; /*this indicates that inserting a new value in the matrix that generates a new nonzero is an error*/ 5248 aij->free_a = PETSC_FALSE; 5249 aij->free_ij = PETSC_FALSE; 5250 5251 for (ii = 0, aij->nonzerorowcnt = 0, aij->rmax = 0; ii < m; ii++) { 5252 aij->ilen[ii] = aij->imax[ii] = i[ii + 1] - i[ii]; 5253 if (PetscDefined(USE_DEBUG)) { 5254 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]); 5255 for (jj = i[ii] + 1; jj < i[ii + 1]; jj++) { 5256 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); 5257 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); 5258 } 5259 } 5260 } 5261 if (PetscDefined(USE_DEBUG)) { 5262 for (ii = 0; ii < aij->i[m]; ii++) { 5263 PetscCheck(j[ii] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative column index at location = %" PetscInt_FMT " index = %" PetscInt_FMT, ii, j[ii]); 5264 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); 5265 } 5266 } 5267 5268 PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY)); 5269 PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY)); 5270 PetscFunctionReturn(PETSC_SUCCESS); 5271 } 5272 5273 /*@ 5274 MatCreateSeqAIJFromTriple - Creates an sequential `MATSEQAIJ` matrix using matrix elements (in COO format) 5275 provided by the user. 5276 5277 Collective 5278 5279 Input Parameters: 5280 + comm - must be an MPI communicator of size 1 5281 . m - number of rows 5282 . n - number of columns 5283 . i - row indices 5284 . j - column indices 5285 . a - matrix values 5286 . nz - number of nonzeros 5287 - idx - if the `i` and `j` indices start with 1 use `PETSC_TRUE` otherwise use `PETSC_FALSE` 5288 5289 Output Parameter: 5290 . mat - the matrix 5291 5292 Level: intermediate 5293 5294 Example: 5295 For the following matrix, the input data expected is as shown (using 0 based indexing) 5296 .vb 5297 1 0 0 5298 2 0 3 5299 4 5 6 5300 5301 i = {0,1,1,2,2,2} 5302 j = {0,0,2,0,1,2} 5303 v = {1,2,3,4,5,6} 5304 .ve 5305 5306 Note: 5307 Instead of using this function, users should also consider `MatSetPreallocationCOO()` and `MatSetValuesCOO()`, which allow repeated or remote entries, 5308 and are particularly useful in iterative applications. 5309 5310 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MatCreateSeqAIJWithArrays()`, `MatMPIAIJSetPreallocationCSR()`, `MatSetValuesCOO()`, `MatSetPreallocationCOO()` 5311 @*/ 5312 PetscErrorCode MatCreateSeqAIJFromTriple(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt i[], PetscInt j[], PetscScalar a[], Mat *mat, PetscCount nz, PetscBool idx) 5313 { 5314 PetscInt ii, *nnz, one = 1, row, col; 5315 5316 PetscFunctionBegin; 5317 PetscCall(PetscCalloc1(m, &nnz)); 5318 for (ii = 0; ii < nz; ii++) nnz[i[ii] - !!idx] += 1; 5319 PetscCall(MatCreate(comm, mat)); 5320 PetscCall(MatSetSizes(*mat, m, n, m, n)); 5321 PetscCall(MatSetType(*mat, MATSEQAIJ)); 5322 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*mat, 0, nnz)); 5323 for (ii = 0; ii < nz; ii++) { 5324 if (idx) { 5325 row = i[ii] - 1; 5326 col = j[ii] - 1; 5327 } else { 5328 row = i[ii]; 5329 col = j[ii]; 5330 } 5331 PetscCall(MatSetValues(*mat, one, &row, one, &col, &a[ii], ADD_VALUES)); 5332 } 5333 PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY)); 5334 PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY)); 5335 PetscCall(PetscFree(nnz)); 5336 PetscFunctionReturn(PETSC_SUCCESS); 5337 } 5338 5339 PetscErrorCode MatSeqAIJInvalidateDiagonal(Mat A) 5340 { 5341 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 5342 5343 PetscFunctionBegin; 5344 a->idiagvalid = PETSC_FALSE; 5345 a->ibdiagvalid = PETSC_FALSE; 5346 5347 PetscCall(MatSeqAIJInvalidateDiagonal_Inode(A)); 5348 PetscFunctionReturn(PETSC_SUCCESS); 5349 } 5350 5351 PetscErrorCode MatCreateMPIMatConcatenateSeqMat_SeqAIJ(MPI_Comm comm, Mat inmat, PetscInt n, MatReuse scall, Mat *outmat) 5352 { 5353 PetscFunctionBegin; 5354 PetscCall(MatCreateMPIMatConcatenateSeqMat_MPIAIJ(comm, inmat, n, scall, outmat)); 5355 PetscFunctionReturn(PETSC_SUCCESS); 5356 } 5357 5358 /* 5359 Permute A into C's *local* index space using rowemb,colemb. 5360 The embedding are supposed to be injections and the above implies that the range of rowemb is a subset 5361 of [0,m), colemb is in [0,n). 5362 If pattern == DIFFERENT_NONZERO_PATTERN, C is preallocated according to A. 5363 */ 5364 PetscErrorCode MatSetSeqMat_SeqAIJ(Mat C, IS rowemb, IS colemb, MatStructure pattern, Mat B) 5365 { 5366 /* If making this function public, change the error returned in this function away from _PLIB. */ 5367 Mat_SeqAIJ *Baij; 5368 PetscBool seqaij; 5369 PetscInt m, n, *nz, i, j, count; 5370 PetscScalar v; 5371 const PetscInt *rowindices, *colindices; 5372 5373 PetscFunctionBegin; 5374 if (!B) PetscFunctionReturn(PETSC_SUCCESS); 5375 /* Check to make sure the target matrix (and embeddings) are compatible with C and each other. */ 5376 PetscCall(PetscObjectBaseTypeCompare((PetscObject)B, MATSEQAIJ, &seqaij)); 5377 PetscCheck(seqaij, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is of wrong type"); 5378 if (rowemb) { 5379 PetscCall(ISGetLocalSize(rowemb, &m)); 5380 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); 5381 } else { 5382 PetscCheck(C->rmap->n == B->rmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is row-incompatible with the target matrix"); 5383 } 5384 if (colemb) { 5385 PetscCall(ISGetLocalSize(colemb, &n)); 5386 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); 5387 } else { 5388 PetscCheck(C->cmap->n == B->cmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is col-incompatible with the target matrix"); 5389 } 5390 5391 Baij = (Mat_SeqAIJ *)B->data; 5392 if (pattern == DIFFERENT_NONZERO_PATTERN) { 5393 PetscCall(PetscMalloc1(B->rmap->n, &nz)); 5394 for (i = 0; i < B->rmap->n; i++) nz[i] = Baij->i[i + 1] - Baij->i[i]; 5395 PetscCall(MatSeqAIJSetPreallocation(C, 0, nz)); 5396 PetscCall(PetscFree(nz)); 5397 } 5398 if (pattern == SUBSET_NONZERO_PATTERN) PetscCall(MatZeroEntries(C)); 5399 count = 0; 5400 rowindices = NULL; 5401 colindices = NULL; 5402 if (rowemb) PetscCall(ISGetIndices(rowemb, &rowindices)); 5403 if (colemb) PetscCall(ISGetIndices(colemb, &colindices)); 5404 for (i = 0; i < B->rmap->n; i++) { 5405 PetscInt row; 5406 row = i; 5407 if (rowindices) row = rowindices[i]; 5408 for (j = Baij->i[i]; j < Baij->i[i + 1]; j++) { 5409 PetscInt col; 5410 col = Baij->j[count]; 5411 if (colindices) col = colindices[col]; 5412 v = Baij->a[count]; 5413 PetscCall(MatSetValues(C, 1, &row, 1, &col, &v, INSERT_VALUES)); 5414 ++count; 5415 } 5416 } 5417 /* FIXME: set C's nonzerostate correctly. */ 5418 /* Assembly for C is necessary. */ 5419 C->preallocated = PETSC_TRUE; 5420 C->assembled = PETSC_TRUE; 5421 C->was_assembled = PETSC_FALSE; 5422 PetscFunctionReturn(PETSC_SUCCESS); 5423 } 5424 5425 PetscErrorCode MatEliminateZeros_SeqAIJ(Mat A, PetscBool keep) 5426 { 5427 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 5428 MatScalar *aa = a->a; 5429 PetscInt m = A->rmap->n, fshift = 0, fshift_prev = 0, i, k; 5430 PetscInt *ailen = a->ilen, *imax = a->imax, *ai = a->i, *aj = a->j, rmax = 0; 5431 5432 PetscFunctionBegin; 5433 PetscCheck(A->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot eliminate zeros for unassembled matrix"); 5434 if (m) rmax = ailen[0]; /* determine row with most nonzeros */ 5435 for (i = 1; i <= m; i++) { 5436 /* move each nonzero entry back by the amount of zero slots (fshift) before it*/ 5437 for (k = ai[i - 1]; k < ai[i]; k++) { 5438 if (aa[k] == 0 && (aj[k] != i - 1 || !keep)) fshift++; 5439 else { 5440 if (aa[k] == 0 && aj[k] == i - 1) PetscCall(PetscInfo(A, "Keep the diagonal zero at row %" PetscInt_FMT "\n", i - 1)); 5441 aa[k - fshift] = aa[k]; 5442 aj[k - fshift] = aj[k]; 5443 } 5444 } 5445 ai[i - 1] -= fshift_prev; // safe to update ai[i-1] now since it will not be used in the next iteration 5446 fshift_prev = fshift; 5447 /* reset ilen and imax for each row */ 5448 ailen[i - 1] = imax[i - 1] = ai[i] - fshift - ai[i - 1]; 5449 a->nonzerorowcnt += ((ai[i] - fshift - ai[i - 1]) > 0); 5450 rmax = PetscMax(rmax, ailen[i - 1]); 5451 } 5452 if (fshift) { 5453 if (m) { 5454 ai[m] -= fshift; 5455 a->nz = ai[m]; 5456 } 5457 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)); 5458 A->nonzerostate++; 5459 A->info.nz_unneeded += (PetscReal)fshift; 5460 a->rmax = rmax; 5461 if (a->inode.use && a->inode.checked) PetscCall(MatSeqAIJCheckInode(A)); 5462 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 5463 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 5464 } 5465 PetscFunctionReturn(PETSC_SUCCESS); 5466 } 5467 5468 PetscFunctionList MatSeqAIJList = NULL; 5469 5470 /*@ 5471 MatSeqAIJSetType - Converts a `MATSEQAIJ` matrix to a subtype 5472 5473 Collective 5474 5475 Input Parameters: 5476 + mat - the matrix object 5477 - matype - matrix type 5478 5479 Options Database Key: 5480 . -mat_seqaij_type <method> - for example seqaijcrl 5481 5482 Level: intermediate 5483 5484 .seealso: [](ch_matrices), `Mat`, `PCSetType()`, `VecSetType()`, `MatCreate()`, `MatType` 5485 @*/ 5486 PetscErrorCode MatSeqAIJSetType(Mat mat, MatType matype) 5487 { 5488 PetscBool sametype; 5489 PetscErrorCode (*r)(Mat, MatType, MatReuse, Mat *); 5490 5491 PetscFunctionBegin; 5492 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 5493 PetscCall(PetscObjectTypeCompare((PetscObject)mat, matype, &sametype)); 5494 if (sametype) PetscFunctionReturn(PETSC_SUCCESS); 5495 5496 PetscCall(PetscFunctionListFind(MatSeqAIJList, matype, &r)); 5497 PetscCheck(r, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown Mat type given: %s", matype); 5498 PetscCall((*r)(mat, matype, MAT_INPLACE_MATRIX, &mat)); 5499 PetscFunctionReturn(PETSC_SUCCESS); 5500 } 5501 5502 /*@C 5503 MatSeqAIJRegister - - Adds a new sub-matrix type for sequential `MATSEQAIJ` matrices 5504 5505 Not Collective, No Fortran Support 5506 5507 Input Parameters: 5508 + sname - name of a new user-defined matrix type, for example `MATSEQAIJCRL` 5509 - function - routine to convert to subtype 5510 5511 Level: advanced 5512 5513 Notes: 5514 `MatSeqAIJRegister()` may be called multiple times to add several user-defined solvers. 5515 5516 Then, your matrix can be chosen with the procedural interface at runtime via the option 5517 $ -mat_seqaij_type my_mat 5518 5519 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJRegisterAll()` 5520 @*/ 5521 PetscErrorCode MatSeqAIJRegister(const char sname[], PetscErrorCode (*function)(Mat, MatType, MatReuse, Mat *)) 5522 { 5523 PetscFunctionBegin; 5524 PetscCall(MatInitializePackage()); 5525 PetscCall(PetscFunctionListAdd(&MatSeqAIJList, sname, function)); 5526 PetscFunctionReturn(PETSC_SUCCESS); 5527 } 5528 5529 PetscBool MatSeqAIJRegisterAllCalled = PETSC_FALSE; 5530 5531 /*@C 5532 MatSeqAIJRegisterAll - Registers all of the matrix subtypes of `MATSSEQAIJ` 5533 5534 Not Collective 5535 5536 Level: advanced 5537 5538 Note: 5539 This registers the versions of `MATSEQAIJ` for GPUs 5540 5541 .seealso: [](ch_matrices), `Mat`, `MatRegisterAll()`, `MatSeqAIJRegister()` 5542 @*/ 5543 PetscErrorCode MatSeqAIJRegisterAll(void) 5544 { 5545 PetscFunctionBegin; 5546 if (MatSeqAIJRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS); 5547 MatSeqAIJRegisterAllCalled = PETSC_TRUE; 5548 5549 PetscCall(MatSeqAIJRegister(MATSEQAIJCRL, MatConvert_SeqAIJ_SeqAIJCRL)); 5550 PetscCall(MatSeqAIJRegister(MATSEQAIJPERM, MatConvert_SeqAIJ_SeqAIJPERM)); 5551 PetscCall(MatSeqAIJRegister(MATSEQAIJSELL, MatConvert_SeqAIJ_SeqAIJSELL)); 5552 #if defined(PETSC_HAVE_MKL_SPARSE) 5553 PetscCall(MatSeqAIJRegister(MATSEQAIJMKL, MatConvert_SeqAIJ_SeqAIJMKL)); 5554 #endif 5555 #if defined(PETSC_HAVE_CUDA) 5556 PetscCall(MatSeqAIJRegister(MATSEQAIJCUSPARSE, MatConvert_SeqAIJ_SeqAIJCUSPARSE)); 5557 #endif 5558 #if defined(PETSC_HAVE_HIP) 5559 PetscCall(MatSeqAIJRegister(MATSEQAIJHIPSPARSE, MatConvert_SeqAIJ_SeqAIJHIPSPARSE)); 5560 #endif 5561 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 5562 PetscCall(MatSeqAIJRegister(MATSEQAIJKOKKOS, MatConvert_SeqAIJ_SeqAIJKokkos)); 5563 #endif 5564 #if defined(PETSC_HAVE_VIENNACL) && defined(PETSC_HAVE_VIENNACL_NO_CUDA) 5565 PetscCall(MatSeqAIJRegister(MATMPIAIJVIENNACL, MatConvert_SeqAIJ_SeqAIJViennaCL)); 5566 #endif 5567 PetscFunctionReturn(PETSC_SUCCESS); 5568 } 5569 5570 /* 5571 Special version for direct calls from Fortran 5572 */ 5573 #if defined(PETSC_HAVE_FORTRAN_CAPS) 5574 #define matsetvaluesseqaij_ MATSETVALUESSEQAIJ 5575 #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE) 5576 #define matsetvaluesseqaij_ matsetvaluesseqaij 5577 #endif 5578 5579 /* Change these macros so can be used in void function */ 5580 5581 /* Change these macros so can be used in void function */ 5582 /* Identical to PetscCallVoid, except it assigns to *_ierr */ 5583 #undef PetscCall 5584 #define PetscCall(...) \ 5585 do { \ 5586 PetscErrorCode ierr_msv_mpiaij = __VA_ARGS__; \ 5587 if (PetscUnlikely(ierr_msv_mpiaij)) { \ 5588 *_ierr = PetscError(PETSC_COMM_SELF, __LINE__, PETSC_FUNCTION_NAME, __FILE__, ierr_msv_mpiaij, PETSC_ERROR_REPEAT, " "); \ 5589 return; \ 5590 } \ 5591 } while (0) 5592 5593 #undef SETERRQ 5594 #define SETERRQ(comm, ierr, ...) \ 5595 do { \ 5596 *_ierr = PetscError(comm, __LINE__, PETSC_FUNCTION_NAME, __FILE__, ierr, PETSC_ERROR_INITIAL, __VA_ARGS__); \ 5597 return; \ 5598 } while (0) 5599 5600 PETSC_EXTERN void matsetvaluesseqaij_(Mat *AA, PetscInt *mm, const PetscInt im[], PetscInt *nn, const PetscInt in[], const PetscScalar v[], InsertMode *isis, PetscErrorCode *_ierr) 5601 { 5602 Mat A = *AA; 5603 PetscInt m = *mm, n = *nn; 5604 InsertMode is = *isis; 5605 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 5606 PetscInt *rp, k, low, high, t, ii, row, nrow, i, col, l, rmax, N; 5607 PetscInt *imax, *ai, *ailen; 5608 PetscInt *aj, nonew = a->nonew, lastcol = -1; 5609 MatScalar *ap, value, *aa; 5610 PetscBool ignorezeroentries = a->ignorezeroentries; 5611 PetscBool roworiented = a->roworiented; 5612 5613 PetscFunctionBegin; 5614 MatCheckPreallocated(A, 1); 5615 imax = a->imax; 5616 ai = a->i; 5617 ailen = a->ilen; 5618 aj = a->j; 5619 aa = a->a; 5620 5621 for (k = 0; k < m; k++) { /* loop over added rows */ 5622 row = im[k]; 5623 if (row < 0) continue; 5624 PetscCheck(row < A->rmap->n, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large"); 5625 rp = aj + ai[row]; 5626 ap = aa + ai[row]; 5627 rmax = imax[row]; 5628 nrow = ailen[row]; 5629 low = 0; 5630 high = nrow; 5631 for (l = 0; l < n; l++) { /* loop over added columns */ 5632 if (in[l] < 0) continue; 5633 PetscCheck(in[l] < A->cmap->n, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Column too large"); 5634 col = in[l]; 5635 if (roworiented) value = v[l + k * n]; 5636 else value = v[k + l * m]; 5637 5638 if (value == 0.0 && ignorezeroentries && (is == ADD_VALUES)) continue; 5639 5640 if (col <= lastcol) low = 0; 5641 else high = nrow; 5642 lastcol = col; 5643 while (high - low > 5) { 5644 t = (low + high) / 2; 5645 if (rp[t] > col) high = t; 5646 else low = t; 5647 } 5648 for (i = low; i < high; i++) { 5649 if (rp[i] > col) break; 5650 if (rp[i] == col) { 5651 if (is == ADD_VALUES) ap[i] += value; 5652 else ap[i] = value; 5653 goto noinsert; 5654 } 5655 } 5656 if (value == 0.0 && ignorezeroentries) goto noinsert; 5657 if (nonew == 1) goto noinsert; 5658 PetscCheck(nonew != -1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero in the matrix"); 5659 MatSeqXAIJReallocateAIJ(A, A->rmap->n, 1, nrow, row, col, rmax, aa, ai, aj, rp, ap, imax, nonew, MatScalar); 5660 N = nrow++ - 1; 5661 a->nz++; 5662 high++; 5663 /* shift up all the later entries in this row */ 5664 for (ii = N; ii >= i; ii--) { 5665 rp[ii + 1] = rp[ii]; 5666 ap[ii + 1] = ap[ii]; 5667 } 5668 rp[i] = col; 5669 ap[i] = value; 5670 noinsert:; 5671 low = i + 1; 5672 } 5673 ailen[row] = nrow; 5674 } 5675 PetscFunctionReturnVoid(); 5676 } 5677 /* Undefining these here since they were redefined from their original definition above! No 5678 * other PETSc functions should be defined past this point, as it is impossible to recover the 5679 * original definitions */ 5680 #undef PetscCall 5681 #undef SETERRQ 5682