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