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