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