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