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(VecSet(v, 0.0)); 3114 PetscCall(VecGetArrayWrite(v, &x)); 3115 PetscCall(VecGetLocalSize(v, &n)); 3116 PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 3117 for (i = 0; i < m; i++) { 3118 ncols = ai[1] - ai[0]; 3119 ai++; 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(VecSet(v, 0.0)); 3149 PetscCall(VecGetArrayWrite(v, &x)); 3150 PetscCall(VecGetLocalSize(v, &n)); 3151 PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 3152 for (i = 0; i < m; i++) { 3153 ncols = ai[1] - ai[0]; 3154 ai++; 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(VecSet(v, 0.0)); 3180 PetscCall(VecGetArrayWrite(v, &x)); 3181 PetscCall(VecGetLocalSize(v, &n)); 3182 PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 3183 for (i = 0; i < m; i++) { 3184 ncols = ai[1] - ai[0]; 3185 ai++; 3186 if (ncols == A->cmap->n) { /* row is dense */ 3187 x[i] = *aa; 3188 if (idx) idx[i] = 0; 3189 } else { /* row is sparse so already KNOW maximum is 0.0 or higher */ 3190 x[i] = 0.0; 3191 if (idx) { 3192 for (j = 0; j < ncols; j++) { /* find first implicit 0.0 in the row */ 3193 if (aj[j] > j) { 3194 idx[i] = j; 3195 break; 3196 } 3197 } 3198 /* in case first implicit 0.0 in the row occurs at ncols-th column */ 3199 if (j == ncols && j < A->cmap->n) idx[i] = j; 3200 } 3201 } 3202 for (j = 0; j < ncols; j++) { 3203 if (PetscRealPart(x[i]) < PetscRealPart(*aa)) { 3204 x[i] = *aa; 3205 if (idx) idx[i] = *aj; 3206 } 3207 aa++; 3208 aj++; 3209 } 3210 } 3211 PetscCall(VecRestoreArrayWrite(v, &x)); 3212 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3213 PetscFunctionReturn(PETSC_SUCCESS); 3214 } 3215 3216 static PetscErrorCode MatGetRowMinAbs_SeqAIJ(Mat A, Vec v, PetscInt idx[]) 3217 { 3218 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3219 PetscInt i, j, m = A->rmap->n, *ai, *aj, ncols, n; 3220 PetscScalar *x; 3221 const MatScalar *aa, *av; 3222 3223 PetscFunctionBegin; 3224 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3225 aa = av; 3226 ai = a->i; 3227 aj = a->j; 3228 3229 PetscCall(VecSet(v, 0.0)); 3230 PetscCall(VecGetArrayWrite(v, &x)); 3231 PetscCall(VecGetLocalSize(v, &n)); 3232 PetscCheck(n == m, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector, %" PetscInt_FMT " vs. %" PetscInt_FMT " rows", m, n); 3233 for (i = 0; i < m; i++) { 3234 ncols = ai[1] - ai[0]; 3235 ai++; 3236 if (ncols == A->cmap->n) { /* row is dense */ 3237 x[i] = *aa; 3238 if (idx) idx[i] = 0; 3239 } else { /* row is sparse so already KNOW minimum is 0.0 or higher */ 3240 x[i] = 0.0; 3241 if (idx) { /* find first implicit 0.0 in the row */ 3242 for (j = 0; j < ncols; j++) { 3243 if (aj[j] > j) { 3244 idx[i] = j; 3245 break; 3246 } 3247 } 3248 /* in case first implicit 0.0 in the row occurs at ncols-th column */ 3249 if (j == ncols && j < A->cmap->n) idx[i] = j; 3250 } 3251 } 3252 for (j = 0; j < ncols; j++) { 3253 if (PetscAbsScalar(x[i]) > PetscAbsScalar(*aa)) { 3254 x[i] = *aa; 3255 if (idx) idx[i] = *aj; 3256 } 3257 aa++; 3258 aj++; 3259 } 3260 } 3261 PetscCall(VecRestoreArrayWrite(v, &x)); 3262 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3263 PetscFunctionReturn(PETSC_SUCCESS); 3264 } 3265 3266 static PetscErrorCode MatGetRowMin_SeqAIJ(Mat A, Vec v, PetscInt idx[]) 3267 { 3268 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3269 PetscInt i, j, m = A->rmap->n, ncols, n; 3270 const PetscInt *ai, *aj; 3271 PetscScalar *x; 3272 const MatScalar *aa, *av; 3273 3274 PetscFunctionBegin; 3275 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3276 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3277 aa = av; 3278 ai = a->i; 3279 aj = a->j; 3280 3281 PetscCall(VecSet(v, 0.0)); 3282 PetscCall(VecGetArrayWrite(v, &x)); 3283 PetscCall(VecGetLocalSize(v, &n)); 3284 PetscCheck(n == m, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 3285 for (i = 0; i < m; i++) { 3286 ncols = ai[1] - ai[0]; 3287 ai++; 3288 if (ncols == A->cmap->n) { /* row is dense */ 3289 x[i] = *aa; 3290 if (idx) idx[i] = 0; 3291 } else { /* row is sparse so already KNOW minimum is 0.0 or lower */ 3292 x[i] = 0.0; 3293 if (idx) { /* find first implicit 0.0 in the row */ 3294 for (j = 0; j < ncols; j++) { 3295 if (aj[j] > j) { 3296 idx[i] = j; 3297 break; 3298 } 3299 } 3300 /* in case first implicit 0.0 in the row occurs at ncols-th column */ 3301 if (j == ncols && j < A->cmap->n) idx[i] = j; 3302 } 3303 } 3304 for (j = 0; j < ncols; j++) { 3305 if (PetscRealPart(x[i]) > PetscRealPart(*aa)) { 3306 x[i] = *aa; 3307 if (idx) idx[i] = *aj; 3308 } 3309 aa++; 3310 aj++; 3311 } 3312 } 3313 PetscCall(VecRestoreArrayWrite(v, &x)); 3314 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3315 PetscFunctionReturn(PETSC_SUCCESS); 3316 } 3317 3318 static PetscErrorCode MatInvertBlockDiagonal_SeqAIJ(Mat A, const PetscScalar **values) 3319 { 3320 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3321 PetscInt i, bs = PetscAbs(A->rmap->bs), mbs = A->rmap->n / bs, ipvt[5], bs2 = bs * bs, *v_pivots, ij[7], *IJ, j; 3322 MatScalar *diag, work[25], *v_work; 3323 const PetscReal shift = 0.0; 3324 PetscBool allowzeropivot, zeropivotdetected = PETSC_FALSE; 3325 3326 PetscFunctionBegin; 3327 allowzeropivot = PetscNot(A->erroriffailure); 3328 if (a->ibdiagvalid) { 3329 if (values) *values = a->ibdiag; 3330 PetscFunctionReturn(PETSC_SUCCESS); 3331 } 3332 PetscCall(MatMarkDiagonal_SeqAIJ(A)); 3333 if (!a->ibdiag) { PetscCall(PetscMalloc1(bs2 * mbs, &a->ibdiag)); } 3334 diag = a->ibdiag; 3335 if (values) *values = a->ibdiag; 3336 /* factor and invert each block */ 3337 switch (bs) { 3338 case 1: 3339 for (i = 0; i < mbs; i++) { 3340 PetscCall(MatGetValues(A, 1, &i, 1, &i, diag + i)); 3341 if (PetscAbsScalar(diag[i] + shift) < PETSC_MACHINE_EPSILON) { 3342 if (allowzeropivot) { 3343 A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3344 A->factorerror_zeropivot_value = PetscAbsScalar(diag[i]); 3345 A->factorerror_zeropivot_row = i; 3346 PetscCall(PetscInfo(A, "Zero pivot, row %" PetscInt_FMT " pivot %g tolerance %g\n", i, (double)PetscAbsScalar(diag[i]), (double)PETSC_MACHINE_EPSILON)); 3347 } 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); 3348 } 3349 diag[i] = (PetscScalar)1.0 / (diag[i] + shift); 3350 } 3351 break; 3352 case 2: 3353 for (i = 0; i < mbs; i++) { 3354 ij[0] = 2 * i; 3355 ij[1] = 2 * i + 1; 3356 PetscCall(MatGetValues(A, 2, ij, 2, ij, diag)); 3357 PetscCall(PetscKernel_A_gets_inverse_A_2(diag, shift, allowzeropivot, &zeropivotdetected)); 3358 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3359 PetscCall(PetscKernel_A_gets_transpose_A_2(diag)); 3360 diag += 4; 3361 } 3362 break; 3363 case 3: 3364 for (i = 0; i < mbs; i++) { 3365 ij[0] = 3 * i; 3366 ij[1] = 3 * i + 1; 3367 ij[2] = 3 * i + 2; 3368 PetscCall(MatGetValues(A, 3, ij, 3, ij, diag)); 3369 PetscCall(PetscKernel_A_gets_inverse_A_3(diag, shift, allowzeropivot, &zeropivotdetected)); 3370 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3371 PetscCall(PetscKernel_A_gets_transpose_A_3(diag)); 3372 diag += 9; 3373 } 3374 break; 3375 case 4: 3376 for (i = 0; i < mbs; i++) { 3377 ij[0] = 4 * i; 3378 ij[1] = 4 * i + 1; 3379 ij[2] = 4 * i + 2; 3380 ij[3] = 4 * i + 3; 3381 PetscCall(MatGetValues(A, 4, ij, 4, ij, diag)); 3382 PetscCall(PetscKernel_A_gets_inverse_A_4(diag, shift, allowzeropivot, &zeropivotdetected)); 3383 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3384 PetscCall(PetscKernel_A_gets_transpose_A_4(diag)); 3385 diag += 16; 3386 } 3387 break; 3388 case 5: 3389 for (i = 0; i < mbs; i++) { 3390 ij[0] = 5 * i; 3391 ij[1] = 5 * i + 1; 3392 ij[2] = 5 * i + 2; 3393 ij[3] = 5 * i + 3; 3394 ij[4] = 5 * i + 4; 3395 PetscCall(MatGetValues(A, 5, ij, 5, ij, diag)); 3396 PetscCall(PetscKernel_A_gets_inverse_A_5(diag, ipvt, work, shift, allowzeropivot, &zeropivotdetected)); 3397 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3398 PetscCall(PetscKernel_A_gets_transpose_A_5(diag)); 3399 diag += 25; 3400 } 3401 break; 3402 case 6: 3403 for (i = 0; i < mbs; i++) { 3404 ij[0] = 6 * i; 3405 ij[1] = 6 * i + 1; 3406 ij[2] = 6 * i + 2; 3407 ij[3] = 6 * i + 3; 3408 ij[4] = 6 * i + 4; 3409 ij[5] = 6 * i + 5; 3410 PetscCall(MatGetValues(A, 6, ij, 6, ij, diag)); 3411 PetscCall(PetscKernel_A_gets_inverse_A_6(diag, shift, allowzeropivot, &zeropivotdetected)); 3412 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3413 PetscCall(PetscKernel_A_gets_transpose_A_6(diag)); 3414 diag += 36; 3415 } 3416 break; 3417 case 7: 3418 for (i = 0; i < mbs; i++) { 3419 ij[0] = 7 * i; 3420 ij[1] = 7 * i + 1; 3421 ij[2] = 7 * i + 2; 3422 ij[3] = 7 * i + 3; 3423 ij[4] = 7 * i + 4; 3424 ij[5] = 7 * i + 5; 3425 ij[6] = 7 * i + 6; 3426 PetscCall(MatGetValues(A, 7, ij, 7, ij, diag)); 3427 PetscCall(PetscKernel_A_gets_inverse_A_7(diag, shift, allowzeropivot, &zeropivotdetected)); 3428 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3429 PetscCall(PetscKernel_A_gets_transpose_A_7(diag)); 3430 diag += 49; 3431 } 3432 break; 3433 default: 3434 PetscCall(PetscMalloc3(bs, &v_work, bs, &v_pivots, bs, &IJ)); 3435 for (i = 0; i < mbs; i++) { 3436 for (j = 0; j < bs; j++) IJ[j] = bs * i + j; 3437 PetscCall(MatGetValues(A, bs, IJ, bs, IJ, diag)); 3438 PetscCall(PetscKernel_A_gets_inverse_A(bs, diag, v_pivots, v_work, allowzeropivot, &zeropivotdetected)); 3439 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3440 PetscCall(PetscKernel_A_gets_transpose_A_N(diag, bs)); 3441 diag += bs2; 3442 } 3443 PetscCall(PetscFree3(v_work, v_pivots, IJ)); 3444 } 3445 a->ibdiagvalid = PETSC_TRUE; 3446 PetscFunctionReturn(PETSC_SUCCESS); 3447 } 3448 3449 static PetscErrorCode MatSetRandom_SeqAIJ(Mat x, PetscRandom rctx) 3450 { 3451 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)x->data; 3452 PetscScalar a, *aa; 3453 PetscInt m, n, i, j, col; 3454 3455 PetscFunctionBegin; 3456 if (!x->assembled) { 3457 PetscCall(MatGetSize(x, &m, &n)); 3458 for (i = 0; i < m; i++) { 3459 for (j = 0; j < aij->imax[i]; j++) { 3460 PetscCall(PetscRandomGetValue(rctx, &a)); 3461 col = (PetscInt)(n * PetscRealPart(a)); 3462 PetscCall(MatSetValues(x, 1, &i, 1, &col, &a, ADD_VALUES)); 3463 } 3464 } 3465 } else { 3466 PetscCall(MatSeqAIJGetArrayWrite(x, &aa)); 3467 for (i = 0; i < aij->nz; i++) PetscCall(PetscRandomGetValue(rctx, aa + i)); 3468 PetscCall(MatSeqAIJRestoreArrayWrite(x, &aa)); 3469 } 3470 PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY)); 3471 PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY)); 3472 PetscFunctionReturn(PETSC_SUCCESS); 3473 } 3474 3475 /* Like MatSetRandom_SeqAIJ, but do not set values on columns in range of [low, high) */ 3476 PetscErrorCode MatSetRandomSkipColumnRange_SeqAIJ_Private(Mat x, PetscInt low, PetscInt high, PetscRandom rctx) 3477 { 3478 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)x->data; 3479 PetscScalar a; 3480 PetscInt m, n, i, j, col, nskip; 3481 3482 PetscFunctionBegin; 3483 nskip = high - low; 3484 PetscCall(MatGetSize(x, &m, &n)); 3485 n -= nskip; /* shrink number of columns where nonzeros can be set */ 3486 for (i = 0; i < m; i++) { 3487 for (j = 0; j < aij->imax[i]; j++) { 3488 PetscCall(PetscRandomGetValue(rctx, &a)); 3489 col = (PetscInt)(n * PetscRealPart(a)); 3490 if (col >= low) col += nskip; /* shift col rightward to skip the hole */ 3491 PetscCall(MatSetValues(x, 1, &i, 1, &col, &a, ADD_VALUES)); 3492 } 3493 } 3494 PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY)); 3495 PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY)); 3496 PetscFunctionReturn(PETSC_SUCCESS); 3497 } 3498 3499 static struct _MatOps MatOps_Values = {MatSetValues_SeqAIJ, 3500 MatGetRow_SeqAIJ, 3501 MatRestoreRow_SeqAIJ, 3502 MatMult_SeqAIJ, 3503 /* 4*/ MatMultAdd_SeqAIJ, 3504 MatMultTranspose_SeqAIJ, 3505 MatMultTransposeAdd_SeqAIJ, 3506 NULL, 3507 NULL, 3508 NULL, 3509 /* 10*/ NULL, 3510 MatLUFactor_SeqAIJ, 3511 NULL, 3512 MatSOR_SeqAIJ, 3513 MatTranspose_SeqAIJ, 3514 /*1 5*/ MatGetInfo_SeqAIJ, 3515 MatEqual_SeqAIJ, 3516 MatGetDiagonal_SeqAIJ, 3517 MatDiagonalScale_SeqAIJ, 3518 MatNorm_SeqAIJ, 3519 /* 20*/ NULL, 3520 MatAssemblyEnd_SeqAIJ, 3521 MatSetOption_SeqAIJ, 3522 MatZeroEntries_SeqAIJ, 3523 /* 24*/ MatZeroRows_SeqAIJ, 3524 NULL, 3525 NULL, 3526 NULL, 3527 NULL, 3528 /* 29*/ MatSetUp_Seq_Hash, 3529 NULL, 3530 NULL, 3531 NULL, 3532 NULL, 3533 /* 34*/ MatDuplicate_SeqAIJ, 3534 NULL, 3535 NULL, 3536 MatILUFactor_SeqAIJ, 3537 NULL, 3538 /* 39*/ MatAXPY_SeqAIJ, 3539 MatCreateSubMatrices_SeqAIJ, 3540 MatIncreaseOverlap_SeqAIJ, 3541 MatGetValues_SeqAIJ, 3542 MatCopy_SeqAIJ, 3543 /* 44*/ MatGetRowMax_SeqAIJ, 3544 MatScale_SeqAIJ, 3545 MatShift_SeqAIJ, 3546 MatDiagonalSet_SeqAIJ, 3547 MatZeroRowsColumns_SeqAIJ, 3548 /* 49*/ MatSetRandom_SeqAIJ, 3549 MatGetRowIJ_SeqAIJ, 3550 MatRestoreRowIJ_SeqAIJ, 3551 MatGetColumnIJ_SeqAIJ, 3552 MatRestoreColumnIJ_SeqAIJ, 3553 /* 54*/ MatFDColoringCreate_SeqXAIJ, 3554 NULL, 3555 NULL, 3556 MatPermute_SeqAIJ, 3557 NULL, 3558 /* 59*/ NULL, 3559 MatDestroy_SeqAIJ, 3560 MatView_SeqAIJ, 3561 NULL, 3562 NULL, 3563 /* 64*/ NULL, 3564 MatMatMatMultNumeric_SeqAIJ_SeqAIJ_SeqAIJ, 3565 NULL, 3566 NULL, 3567 NULL, 3568 /* 69*/ MatGetRowMaxAbs_SeqAIJ, 3569 MatGetRowMinAbs_SeqAIJ, 3570 NULL, 3571 NULL, 3572 NULL, 3573 /* 74*/ NULL, 3574 MatFDColoringApply_AIJ, 3575 NULL, 3576 NULL, 3577 NULL, 3578 /* 79*/ MatFindZeroDiagonals_SeqAIJ, 3579 NULL, 3580 NULL, 3581 NULL, 3582 MatLoad_SeqAIJ, 3583 /* 84*/ NULL, 3584 NULL, 3585 NULL, 3586 NULL, 3587 NULL, 3588 /* 89*/ NULL, 3589 NULL, 3590 MatMatMultNumeric_SeqAIJ_SeqAIJ, 3591 NULL, 3592 NULL, 3593 /* 94*/ MatPtAPNumeric_SeqAIJ_SeqAIJ_SparseAxpy, 3594 NULL, 3595 NULL, 3596 MatMatTransposeMultNumeric_SeqAIJ_SeqAIJ, 3597 NULL, 3598 /* 99*/ MatProductSetFromOptions_SeqAIJ, 3599 NULL, 3600 NULL, 3601 MatConjugate_SeqAIJ, 3602 NULL, 3603 /*104*/ MatSetValuesRow_SeqAIJ, 3604 MatRealPart_SeqAIJ, 3605 MatImaginaryPart_SeqAIJ, 3606 NULL, 3607 NULL, 3608 /*109*/ MatMatSolve_SeqAIJ, 3609 NULL, 3610 MatGetRowMin_SeqAIJ, 3611 NULL, 3612 MatMissingDiagonal_SeqAIJ, 3613 /*114*/ NULL, 3614 NULL, 3615 NULL, 3616 NULL, 3617 NULL, 3618 /*119*/ NULL, 3619 NULL, 3620 NULL, 3621 NULL, 3622 MatGetMultiProcBlock_SeqAIJ, 3623 /*124*/ MatFindNonzeroRows_SeqAIJ, 3624 MatGetColumnReductions_SeqAIJ, 3625 MatInvertBlockDiagonal_SeqAIJ, 3626 MatInvertVariableBlockDiagonal_SeqAIJ, 3627 NULL, 3628 /*129*/ NULL, 3629 NULL, 3630 NULL, 3631 MatTransposeMatMultNumeric_SeqAIJ_SeqAIJ, 3632 MatTransposeColoringCreate_SeqAIJ, 3633 /*134*/ MatTransColoringApplySpToDen_SeqAIJ, 3634 MatTransColoringApplyDenToSp_SeqAIJ, 3635 NULL, 3636 NULL, 3637 MatRARtNumeric_SeqAIJ_SeqAIJ, 3638 /*139*/ NULL, 3639 NULL, 3640 NULL, 3641 MatFDColoringSetUp_SeqXAIJ, 3642 MatFindOffBlockDiagonalEntries_SeqAIJ, 3643 MatCreateMPIMatConcatenateSeqMat_SeqAIJ, 3644 /*145*/ MatDestroySubMatrices_SeqAIJ, 3645 NULL, 3646 NULL, 3647 MatCreateGraph_Simple_AIJ, 3648 NULL, 3649 /*150*/ MatTransposeSymbolic_SeqAIJ, 3650 MatEliminateZeros_SeqAIJ, 3651 MatGetRowSumAbs_SeqAIJ, 3652 NULL, 3653 NULL, 3654 /*155*/ NULL, 3655 MatCopyHashToXAIJ_Seq_Hash}; 3656 3657 static PetscErrorCode MatSeqAIJSetColumnIndices_SeqAIJ(Mat mat, PetscInt *indices) 3658 { 3659 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3660 PetscInt i, nz, n; 3661 3662 PetscFunctionBegin; 3663 nz = aij->maxnz; 3664 n = mat->rmap->n; 3665 for (i = 0; i < nz; i++) aij->j[i] = indices[i]; 3666 aij->nz = nz; 3667 for (i = 0; i < n; i++) aij->ilen[i] = aij->imax[i]; 3668 PetscFunctionReturn(PETSC_SUCCESS); 3669 } 3670 3671 /* 3672 * Given a sparse matrix with global column indices, compact it by using a local column space. 3673 * The result matrix helps saving memory in other algorithms, such as MatPtAPSymbolic_MPIAIJ_MPIAIJ_scalable() 3674 */ 3675 PetscErrorCode MatSeqAIJCompactOutExtraColumns_SeqAIJ(Mat mat, ISLocalToGlobalMapping *mapping) 3676 { 3677 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3678 PetscHMapI gid1_lid1; 3679 PetscHashIter tpos; 3680 PetscInt gid, lid, i, ec, nz = aij->nz; 3681 PetscInt *garray, *jj = aij->j; 3682 3683 PetscFunctionBegin; 3684 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3685 PetscAssertPointer(mapping, 2); 3686 /* use a table */ 3687 PetscCall(PetscHMapICreateWithSize(mat->rmap->n, &gid1_lid1)); 3688 ec = 0; 3689 for (i = 0; i < nz; i++) { 3690 PetscInt data, gid1 = jj[i] + 1; 3691 PetscCall(PetscHMapIGetWithDefault(gid1_lid1, gid1, 0, &data)); 3692 if (!data) { 3693 /* one based table */ 3694 PetscCall(PetscHMapISet(gid1_lid1, gid1, ++ec)); 3695 } 3696 } 3697 /* form array of columns we need */ 3698 PetscCall(PetscMalloc1(ec, &garray)); 3699 PetscHashIterBegin(gid1_lid1, tpos); 3700 while (!PetscHashIterAtEnd(gid1_lid1, tpos)) { 3701 PetscHashIterGetKey(gid1_lid1, tpos, gid); 3702 PetscHashIterGetVal(gid1_lid1, tpos, lid); 3703 PetscHashIterNext(gid1_lid1, tpos); 3704 gid--; 3705 lid--; 3706 garray[lid] = gid; 3707 } 3708 PetscCall(PetscSortInt(ec, garray)); /* sort, and rebuild */ 3709 PetscCall(PetscHMapIClear(gid1_lid1)); 3710 for (i = 0; i < ec; i++) PetscCall(PetscHMapISet(gid1_lid1, garray[i] + 1, i + 1)); 3711 /* compact out the extra columns in B */ 3712 for (i = 0; i < nz; i++) { 3713 PetscInt gid1 = jj[i] + 1; 3714 PetscCall(PetscHMapIGetWithDefault(gid1_lid1, gid1, 0, &lid)); 3715 lid--; 3716 jj[i] = lid; 3717 } 3718 PetscCall(PetscLayoutDestroy(&mat->cmap)); 3719 PetscCall(PetscHMapIDestroy(&gid1_lid1)); 3720 PetscCall(PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)mat), ec, ec, 1, &mat->cmap)); 3721 PetscCall(ISLocalToGlobalMappingCreate(PETSC_COMM_SELF, mat->cmap->bs, mat->cmap->n, garray, PETSC_OWN_POINTER, mapping)); 3722 PetscCall(ISLocalToGlobalMappingSetType(*mapping, ISLOCALTOGLOBALMAPPINGHASH)); 3723 PetscFunctionReturn(PETSC_SUCCESS); 3724 } 3725 3726 /*@ 3727 MatSeqAIJSetColumnIndices - Set the column indices for all the rows 3728 in the matrix. 3729 3730 Input Parameters: 3731 + mat - the `MATSEQAIJ` matrix 3732 - indices - the column indices 3733 3734 Level: advanced 3735 3736 Notes: 3737 This can be called if you have precomputed the nonzero structure of the 3738 matrix and want to provide it to the matrix object to improve the performance 3739 of the `MatSetValues()` operation. 3740 3741 You MUST have set the correct numbers of nonzeros per row in the call to 3742 `MatCreateSeqAIJ()`, and the columns indices MUST be sorted. 3743 3744 MUST be called before any calls to `MatSetValues()` 3745 3746 The indices should start with zero, not one. 3747 3748 .seealso: [](ch_matrices), `Mat`, `MATSEQAIJ` 3749 @*/ 3750 PetscErrorCode MatSeqAIJSetColumnIndices(Mat mat, PetscInt *indices) 3751 { 3752 PetscFunctionBegin; 3753 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3754 PetscAssertPointer(indices, 2); 3755 PetscUseMethod(mat, "MatSeqAIJSetColumnIndices_C", (Mat, PetscInt *), (mat, indices)); 3756 PetscFunctionReturn(PETSC_SUCCESS); 3757 } 3758 3759 static PetscErrorCode MatStoreValues_SeqAIJ(Mat mat) 3760 { 3761 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3762 size_t nz = aij->i[mat->rmap->n]; 3763 3764 PetscFunctionBegin; 3765 PetscCheck(aij->nonew, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first"); 3766 3767 /* allocate space for values if not already there */ 3768 if (!aij->saved_values) { PetscCall(PetscMalloc1(nz + 1, &aij->saved_values)); } 3769 3770 /* copy values over */ 3771 PetscCall(PetscArraycpy(aij->saved_values, aij->a, nz)); 3772 PetscFunctionReturn(PETSC_SUCCESS); 3773 } 3774 3775 /*@ 3776 MatStoreValues - Stashes a copy of the matrix values; this allows reusing of the linear part of a Jacobian, while recomputing only the 3777 nonlinear portion. 3778 3779 Logically Collect 3780 3781 Input Parameter: 3782 . mat - the matrix (currently only `MATAIJ` matrices support this option) 3783 3784 Level: advanced 3785 3786 Example Usage: 3787 .vb 3788 Using SNES 3789 Create Jacobian matrix 3790 Set linear terms into matrix 3791 Apply boundary conditions to matrix, at this time matrix must have 3792 final nonzero structure (i.e. setting the nonlinear terms and applying 3793 boundary conditions again will not change the nonzero structure 3794 MatSetOption(mat, MAT_NEW_NONZERO_LOCATIONS, PETSC_FALSE); 3795 MatStoreValues(mat); 3796 Call SNESSetJacobian() with matrix 3797 In your Jacobian routine 3798 MatRetrieveValues(mat); 3799 Set nonlinear terms in matrix 3800 3801 Without `SNESSolve()`, i.e. when you handle nonlinear solve yourself: 3802 // build linear portion of Jacobian 3803 MatSetOption(mat, MAT_NEW_NONZERO_LOCATIONS, PETSC_FALSE); 3804 MatStoreValues(mat); 3805 loop over nonlinear iterations 3806 MatRetrieveValues(mat); 3807 // call MatSetValues(mat,...) to set nonliner portion of Jacobian 3808 // call MatAssemblyBegin/End() on matrix 3809 Solve linear system with Jacobian 3810 endloop 3811 .ve 3812 3813 Notes: 3814 Matrix must already be assembled before calling this routine 3815 Must set the matrix option `MatSetOption`(mat,`MAT_NEW_NONZERO_LOCATIONS`,`PETSC_FALSE`); before 3816 calling this routine. 3817 3818 When this is called multiple times it overwrites the previous set of stored values 3819 and does not allocated additional space. 3820 3821 .seealso: [](ch_matrices), `Mat`, `MatRetrieveValues()` 3822 @*/ 3823 PetscErrorCode MatStoreValues(Mat mat) 3824 { 3825 PetscFunctionBegin; 3826 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3827 PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 3828 PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3829 PetscUseMethod(mat, "MatStoreValues_C", (Mat), (mat)); 3830 PetscFunctionReturn(PETSC_SUCCESS); 3831 } 3832 3833 static PetscErrorCode MatRetrieveValues_SeqAIJ(Mat mat) 3834 { 3835 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3836 PetscInt nz = aij->i[mat->rmap->n]; 3837 3838 PetscFunctionBegin; 3839 PetscCheck(aij->nonew, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first"); 3840 PetscCheck(aij->saved_values, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatStoreValues(A);first"); 3841 /* copy values over */ 3842 PetscCall(PetscArraycpy(aij->a, aij->saved_values, nz)); 3843 PetscFunctionReturn(PETSC_SUCCESS); 3844 } 3845 3846 /*@ 3847 MatRetrieveValues - Retrieves the copy of the matrix values that was stored with `MatStoreValues()` 3848 3849 Logically Collect 3850 3851 Input Parameter: 3852 . mat - the matrix (currently only `MATAIJ` matrices support this option) 3853 3854 Level: advanced 3855 3856 .seealso: [](ch_matrices), `Mat`, `MatStoreValues()` 3857 @*/ 3858 PetscErrorCode MatRetrieveValues(Mat mat) 3859 { 3860 PetscFunctionBegin; 3861 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3862 PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 3863 PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3864 PetscUseMethod(mat, "MatRetrieveValues_C", (Mat), (mat)); 3865 PetscFunctionReturn(PETSC_SUCCESS); 3866 } 3867 3868 /*@ 3869 MatCreateSeqAIJ - Creates a sparse matrix in `MATSEQAIJ` (compressed row) format 3870 (the default parallel PETSc format). For good matrix assembly performance 3871 the user should preallocate the matrix storage by setting the parameter `nz` 3872 (or the array `nnz`). 3873 3874 Collective 3875 3876 Input Parameters: 3877 + comm - MPI communicator, set to `PETSC_COMM_SELF` 3878 . m - number of rows 3879 . n - number of columns 3880 . nz - number of nonzeros per row (same for all rows) 3881 - nnz - array containing the number of nonzeros in the various rows 3882 (possibly different for each row) or NULL 3883 3884 Output Parameter: 3885 . A - the matrix 3886 3887 Options Database Keys: 3888 + -mat_no_inode - Do not use inodes 3889 - -mat_inode_limit <limit> - Sets inode limit (max limit=5) 3890 3891 Level: intermediate 3892 3893 Notes: 3894 It is recommend to use `MatCreateFromOptions()` instead of this routine 3895 3896 If `nnz` is given then `nz` is ignored 3897 3898 The `MATSEQAIJ` format, also called 3899 compressed row storage, is fully compatible with standard Fortran 3900 storage. That is, the stored row and column indices can begin at 3901 either one (as in Fortran) or zero. 3902 3903 Specify the preallocated storage with either `nz` or `nnz` (not both). 3904 Set `nz` = `PETSC_DEFAULT` and `nnz` = `NULL` for PETSc to control dynamic memory 3905 allocation. 3906 3907 By default, this format uses inodes (identical nodes) when possible, to 3908 improve numerical efficiency of matrix-vector products and solves. We 3909 search for consecutive rows with the same nonzero structure, thereby 3910 reusing matrix information to achieve increased efficiency. 3911 3912 .seealso: [](ch_matrices), `Mat`, [Sparse Matrix Creation](sec_matsparse), `MatCreate()`, `MatCreateAIJ()`, `MatSetValues()`, `MatSeqAIJSetColumnIndices()`, `MatCreateSeqAIJWithArrays()` 3913 @*/ 3914 PetscErrorCode MatCreateSeqAIJ(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt nz, const PetscInt nnz[], Mat *A) 3915 { 3916 PetscFunctionBegin; 3917 PetscCall(MatCreate(comm, A)); 3918 PetscCall(MatSetSizes(*A, m, n, m, n)); 3919 PetscCall(MatSetType(*A, MATSEQAIJ)); 3920 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*A, nz, nnz)); 3921 PetscFunctionReturn(PETSC_SUCCESS); 3922 } 3923 3924 /*@ 3925 MatSeqAIJSetPreallocation - For good matrix assembly performance 3926 the user should preallocate the matrix storage by setting the parameter nz 3927 (or the array nnz). By setting these parameters accurately, performance 3928 during matrix assembly can be increased by more than a factor of 50. 3929 3930 Collective 3931 3932 Input Parameters: 3933 + B - The matrix 3934 . nz - number of nonzeros per row (same for all rows) 3935 - nnz - array containing the number of nonzeros in the various rows 3936 (possibly different for each row) or NULL 3937 3938 Options Database Keys: 3939 + -mat_no_inode - Do not use inodes 3940 - -mat_inode_limit <limit> - Sets inode limit (max limit=5) 3941 3942 Level: intermediate 3943 3944 Notes: 3945 If `nnz` is given then `nz` is ignored 3946 3947 The `MATSEQAIJ` format also called 3948 compressed row storage, is fully compatible with standard Fortran 3949 storage. That is, the stored row and column indices can begin at 3950 either one (as in Fortran) or zero. See the users' manual for details. 3951 3952 Specify the preallocated storage with either `nz` or `nnz` (not both). 3953 Set nz = `PETSC_DEFAULT` and `nnz` = `NULL` for PETSc to control dynamic memory 3954 allocation. 3955 3956 You can call `MatGetInfo()` to get information on how effective the preallocation was; 3957 for example the fields mallocs,nz_allocated,nz_used,nz_unneeded; 3958 You can also run with the option -info and look for messages with the string 3959 malloc in them to see if additional memory allocation was needed. 3960 3961 Developer Notes: 3962 Use nz of `MAT_SKIP_ALLOCATION` to not allocate any space for the matrix 3963 entries or columns indices 3964 3965 By default, this format uses inodes (identical nodes) when possible, to 3966 improve numerical efficiency of matrix-vector products and solves. We 3967 search for consecutive rows with the same nonzero structure, thereby 3968 reusing matrix information to achieve increased efficiency. 3969 3970 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateAIJ()`, `MatSetValues()`, `MatSeqAIJSetColumnIndices()`, `MatCreateSeqAIJWithArrays()`, `MatGetInfo()`, 3971 `MatSeqAIJSetTotalPreallocation()` 3972 @*/ 3973 PetscErrorCode MatSeqAIJSetPreallocation(Mat B, PetscInt nz, const PetscInt nnz[]) 3974 { 3975 PetscFunctionBegin; 3976 PetscValidHeaderSpecific(B, MAT_CLASSID, 1); 3977 PetscValidType(B, 1); 3978 PetscTryMethod(B, "MatSeqAIJSetPreallocation_C", (Mat, PetscInt, const PetscInt[]), (B, nz, nnz)); 3979 PetscFunctionReturn(PETSC_SUCCESS); 3980 } 3981 3982 PetscErrorCode MatSeqAIJSetPreallocation_SeqAIJ(Mat B, PetscInt nz, const PetscInt *nnz) 3983 { 3984 Mat_SeqAIJ *b = (Mat_SeqAIJ *)B->data; 3985 PetscBool skipallocation = PETSC_FALSE, realalloc = PETSC_FALSE; 3986 PetscInt i; 3987 3988 PetscFunctionBegin; 3989 if (B->hash_active) { 3990 B->ops[0] = b->cops; 3991 PetscCall(PetscHMapIJVDestroy(&b->ht)); 3992 PetscCall(PetscFree(b->dnz)); 3993 B->hash_active = PETSC_FALSE; 3994 } 3995 if (nz >= 0 || nnz) realalloc = PETSC_TRUE; 3996 if (nz == MAT_SKIP_ALLOCATION) { 3997 skipallocation = PETSC_TRUE; 3998 nz = 0; 3999 } 4000 PetscCall(PetscLayoutSetUp(B->rmap)); 4001 PetscCall(PetscLayoutSetUp(B->cmap)); 4002 4003 if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 5; 4004 PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nz cannot be less than 0: value %" PetscInt_FMT, nz); 4005 if (nnz) { 4006 for (i = 0; i < B->rmap->n; i++) { 4007 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]); 4008 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); 4009 } 4010 } 4011 4012 B->preallocated = PETSC_TRUE; 4013 if (!skipallocation) { 4014 if (!b->imax) { PetscCall(PetscMalloc1(B->rmap->n, &b->imax)); } 4015 if (!b->ilen) { 4016 /* b->ilen will count nonzeros in each row so far. */ 4017 PetscCall(PetscCalloc1(B->rmap->n, &b->ilen)); 4018 } else { 4019 PetscCall(PetscMemzero(b->ilen, B->rmap->n * sizeof(PetscInt))); 4020 } 4021 if (!b->ipre) PetscCall(PetscMalloc1(B->rmap->n, &b->ipre)); 4022 if (!nnz) { 4023 if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 10; 4024 else if (nz < 0) nz = 1; 4025 nz = PetscMin(nz, B->cmap->n); 4026 for (i = 0; i < B->rmap->n; i++) b->imax[i] = nz; 4027 PetscCall(PetscIntMultError(nz, B->rmap->n, &nz)); 4028 } else { 4029 PetscInt64 nz64 = 0; 4030 for (i = 0; i < B->rmap->n; i++) { 4031 b->imax[i] = nnz[i]; 4032 nz64 += nnz[i]; 4033 } 4034 PetscCall(PetscIntCast(nz64, &nz)); 4035 } 4036 4037 /* allocate the matrix space */ 4038 PetscCall(MatSeqXAIJFreeAIJ(B, &b->a, &b->j, &b->i)); 4039 PetscCall(PetscShmgetAllocateArray(nz, sizeof(PetscInt), (void **)&b->j)); 4040 PetscCall(PetscShmgetAllocateArray(B->rmap->n + 1, sizeof(PetscInt), (void **)&b->i)); 4041 b->free_ij = PETSC_TRUE; 4042 if (B->structure_only) { 4043 b->free_a = PETSC_FALSE; 4044 } else { 4045 PetscCall(PetscShmgetAllocateArray(nz, sizeof(PetscScalar), (void **)&b->a)); 4046 b->free_a = PETSC_TRUE; 4047 } 4048 b->i[0] = 0; 4049 for (i = 1; i < B->rmap->n + 1; i++) b->i[i] = b->i[i - 1] + b->imax[i - 1]; 4050 } else { 4051 b->free_a = PETSC_FALSE; 4052 b->free_ij = PETSC_FALSE; 4053 } 4054 4055 if (b->ipre && nnz != b->ipre && b->imax) { 4056 /* reserve user-requested sparsity */ 4057 PetscCall(PetscArraycpy(b->ipre, b->imax, B->rmap->n)); 4058 } 4059 4060 b->nz = 0; 4061 b->maxnz = nz; 4062 B->info.nz_unneeded = (double)b->maxnz; 4063 if (realalloc) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 4064 B->was_assembled = PETSC_FALSE; 4065 B->assembled = PETSC_FALSE; 4066 /* We simply deem preallocation has changed nonzero state. Updating the state 4067 will give clients (like AIJKokkos) a chance to know something has happened. 4068 */ 4069 B->nonzerostate++; 4070 PetscFunctionReturn(PETSC_SUCCESS); 4071 } 4072 4073 static PetscErrorCode MatResetPreallocation_SeqAIJ(Mat A) 4074 { 4075 Mat_SeqAIJ *a; 4076 PetscInt i; 4077 PetscBool skipreset; 4078 4079 PetscFunctionBegin; 4080 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 4081 4082 /* Check local size. If zero, then return */ 4083 if (!A->rmap->n) PetscFunctionReturn(PETSC_SUCCESS); 4084 4085 a = (Mat_SeqAIJ *)A->data; 4086 /* if no saved info, we error out */ 4087 PetscCheck(a->ipre, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "No saved preallocation info "); 4088 4089 PetscCheck(a->i && a->imax && a->ilen, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Memory info is incomplete, and can not reset preallocation "); 4090 4091 PetscCall(PetscArraycmp(a->ipre, a->ilen, A->rmap->n, &skipreset)); 4092 if (!skipreset) { 4093 PetscCall(PetscArraycpy(a->imax, a->ipre, A->rmap->n)); 4094 PetscCall(PetscArrayzero(a->ilen, A->rmap->n)); 4095 a->i[0] = 0; 4096 for (i = 1; i < A->rmap->n + 1; i++) a->i[i] = a->i[i - 1] + a->imax[i - 1]; 4097 A->preallocated = PETSC_TRUE; 4098 a->nz = 0; 4099 a->maxnz = a->i[A->rmap->n]; 4100 A->info.nz_unneeded = (double)a->maxnz; 4101 A->was_assembled = PETSC_FALSE; 4102 A->assembled = PETSC_FALSE; 4103 } 4104 PetscFunctionReturn(PETSC_SUCCESS); 4105 } 4106 4107 /*@ 4108 MatSeqAIJSetPreallocationCSR - Allocates memory for a sparse sequential matrix in `MATSEQAIJ` format. 4109 4110 Input Parameters: 4111 + B - the matrix 4112 . i - the indices into `j` for the start of each row (indices start with zero) 4113 . j - the column indices for each row (indices start with zero) these must be sorted for each row 4114 - v - optional values in the matrix, use `NULL` if not provided 4115 4116 Level: developer 4117 4118 Notes: 4119 The `i`,`j`,`v` values are COPIED with this routine; to avoid the copy use `MatCreateSeqAIJWithArrays()` 4120 4121 This routine may be called multiple times with different nonzero patterns (or the same nonzero pattern). The nonzero 4122 structure will be the union of all the previous nonzero structures. 4123 4124 Developer Notes: 4125 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 4126 then just copies the `v` values directly with `PetscMemcpy()`. 4127 4128 This routine could also take a `PetscCopyMode` argument to allow sharing the values instead of always copying them. 4129 4130 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateSeqAIJ()`, `MatSetValues()`, `MatSeqAIJSetPreallocation()`, `MATSEQAIJ`, `MatResetPreallocation()` 4131 @*/ 4132 PetscErrorCode MatSeqAIJSetPreallocationCSR(Mat B, const PetscInt i[], const PetscInt j[], const PetscScalar v[]) 4133 { 4134 PetscFunctionBegin; 4135 PetscValidHeaderSpecific(B, MAT_CLASSID, 1); 4136 PetscValidType(B, 1); 4137 PetscTryMethod(B, "MatSeqAIJSetPreallocationCSR_C", (Mat, const PetscInt[], const PetscInt[], const PetscScalar[]), (B, i, j, v)); 4138 PetscFunctionReturn(PETSC_SUCCESS); 4139 } 4140 4141 static PetscErrorCode MatSeqAIJSetPreallocationCSR_SeqAIJ(Mat B, const PetscInt Ii[], const PetscInt J[], const PetscScalar v[]) 4142 { 4143 PetscInt i; 4144 PetscInt m, n; 4145 PetscInt nz; 4146 PetscInt *nnz; 4147 4148 PetscFunctionBegin; 4149 PetscCheck(Ii[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Ii[0] must be 0 it is %" PetscInt_FMT, Ii[0]); 4150 4151 PetscCall(PetscLayoutSetUp(B->rmap)); 4152 PetscCall(PetscLayoutSetUp(B->cmap)); 4153 4154 PetscCall(MatGetSize(B, &m, &n)); 4155 PetscCall(PetscMalloc1(m + 1, &nnz)); 4156 for (i = 0; i < m; i++) { 4157 nz = Ii[i + 1] - Ii[i]; 4158 PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local row %" PetscInt_FMT " has a negative number of columns %" PetscInt_FMT, i, nz); 4159 nnz[i] = nz; 4160 } 4161 PetscCall(MatSeqAIJSetPreallocation(B, 0, nnz)); 4162 PetscCall(PetscFree(nnz)); 4163 4164 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)); 4165 4166 PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY)); 4167 PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY)); 4168 4169 PetscCall(MatSetOption(B, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE)); 4170 PetscFunctionReturn(PETSC_SUCCESS); 4171 } 4172 4173 /*@ 4174 MatSeqAIJKron - Computes `C`, the Kronecker product of `A` and `B`. 4175 4176 Input Parameters: 4177 + A - left-hand side matrix 4178 . B - right-hand side matrix 4179 - reuse - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX` 4180 4181 Output Parameter: 4182 . C - Kronecker product of `A` and `B` 4183 4184 Level: intermediate 4185 4186 Note: 4187 `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the product matrix has not changed from that last call to `MatSeqAIJKron()`. 4188 4189 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MATKAIJ`, `MatReuse` 4190 @*/ 4191 PetscErrorCode MatSeqAIJKron(Mat A, Mat B, MatReuse reuse, Mat *C) 4192 { 4193 PetscFunctionBegin; 4194 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 4195 PetscValidType(A, 1); 4196 PetscValidHeaderSpecific(B, MAT_CLASSID, 2); 4197 PetscValidType(B, 2); 4198 PetscAssertPointer(C, 4); 4199 if (reuse == MAT_REUSE_MATRIX) { 4200 PetscValidHeaderSpecific(*C, MAT_CLASSID, 4); 4201 PetscValidType(*C, 4); 4202 } 4203 PetscTryMethod(A, "MatSeqAIJKron_C", (Mat, Mat, MatReuse, Mat *), (A, B, reuse, C)); 4204 PetscFunctionReturn(PETSC_SUCCESS); 4205 } 4206 4207 static PetscErrorCode MatSeqAIJKron_SeqAIJ(Mat A, Mat B, MatReuse reuse, Mat *C) 4208 { 4209 Mat newmat; 4210 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 4211 Mat_SeqAIJ *b = (Mat_SeqAIJ *)B->data; 4212 PetscScalar *v; 4213 const PetscScalar *aa, *ba; 4214 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; 4215 PetscBool flg; 4216 4217 PetscFunctionBegin; 4218 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 4219 PetscCheck(A->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 4220 PetscCheck(!B->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 4221 PetscCheck(B->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 4222 PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &flg)); 4223 PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatType %s", ((PetscObject)B)->type_name); 4224 PetscCheck(reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatReuse %d", (int)reuse); 4225 if (reuse == MAT_INITIAL_MATRIX) { 4226 PetscCall(PetscMalloc2(am * bm + 1, &i, a->i[am] * b->i[bm], &j)); 4227 PetscCall(MatCreate(PETSC_COMM_SELF, &newmat)); 4228 PetscCall(MatSetSizes(newmat, am * bm, an * bn, am * bm, an * bn)); 4229 PetscCall(MatSetType(newmat, MATAIJ)); 4230 i[0] = 0; 4231 for (m = 0; m < am; ++m) { 4232 for (p = 0; p < bm; ++p) { 4233 i[m * bm + p + 1] = i[m * bm + p] + (a->i[m + 1] - a->i[m]) * (b->i[p + 1] - b->i[p]); 4234 for (n = a->i[m]; n < a->i[m + 1]; ++n) { 4235 for (q = b->i[p]; q < b->i[p + 1]; ++q) j[nnz++] = a->j[n] * bn + b->j[q]; 4236 } 4237 } 4238 } 4239 PetscCall(MatSeqAIJSetPreallocationCSR(newmat, i, j, NULL)); 4240 *C = newmat; 4241 PetscCall(PetscFree2(i, j)); 4242 nnz = 0; 4243 } 4244 PetscCall(MatSeqAIJGetArray(*C, &v)); 4245 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 4246 PetscCall(MatSeqAIJGetArrayRead(B, &ba)); 4247 for (m = 0; m < am; ++m) { 4248 for (p = 0; p < bm; ++p) { 4249 for (n = a->i[m]; n < a->i[m + 1]; ++n) { 4250 for (q = b->i[p]; q < b->i[p + 1]; ++q) v[nnz++] = aa[n] * ba[q]; 4251 } 4252 } 4253 } 4254 PetscCall(MatSeqAIJRestoreArray(*C, &v)); 4255 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 4256 PetscCall(MatSeqAIJRestoreArrayRead(B, &ba)); 4257 PetscFunctionReturn(PETSC_SUCCESS); 4258 } 4259 4260 #include <../src/mat/impls/dense/seq/dense.h> 4261 #include <petsc/private/kernels/petscaxpy.h> 4262 4263 /* 4264 Computes (B'*A')' since computing B*A directly is untenable 4265 4266 n p p 4267 [ ] [ ] [ ] 4268 m [ A ] * n [ B ] = m [ C ] 4269 [ ] [ ] [ ] 4270 4271 */ 4272 PetscErrorCode MatMatMultNumeric_SeqDense_SeqAIJ(Mat A, Mat B, Mat C) 4273 { 4274 Mat_SeqDense *sub_a = (Mat_SeqDense *)A->data; 4275 Mat_SeqAIJ *sub_b = (Mat_SeqAIJ *)B->data; 4276 Mat_SeqDense *sub_c = (Mat_SeqDense *)C->data; 4277 PetscInt i, j, n, m, q, p; 4278 const PetscInt *ii, *idx; 4279 const PetscScalar *b, *a, *a_q; 4280 PetscScalar *c, *c_q; 4281 PetscInt clda = sub_c->lda; 4282 PetscInt alda = sub_a->lda; 4283 4284 PetscFunctionBegin; 4285 m = A->rmap->n; 4286 n = A->cmap->n; 4287 p = B->cmap->n; 4288 a = sub_a->v; 4289 b = sub_b->a; 4290 c = sub_c->v; 4291 if (clda == m) { 4292 PetscCall(PetscArrayzero(c, m * p)); 4293 } else { 4294 for (j = 0; j < p; j++) 4295 for (i = 0; i < m; i++) c[j * clda + i] = 0.0; 4296 } 4297 ii = sub_b->i; 4298 idx = sub_b->j; 4299 for (i = 0; i < n; i++) { 4300 q = ii[i + 1] - ii[i]; 4301 while (q-- > 0) { 4302 c_q = c + clda * (*idx); 4303 a_q = a + alda * i; 4304 PetscKernelAXPY(c_q, *b, a_q, m); 4305 idx++; 4306 b++; 4307 } 4308 } 4309 PetscFunctionReturn(PETSC_SUCCESS); 4310 } 4311 4312 PetscErrorCode MatMatMultSymbolic_SeqDense_SeqAIJ(Mat A, Mat B, PetscReal fill, Mat C) 4313 { 4314 PetscInt m = A->rmap->n, n = B->cmap->n; 4315 PetscBool cisdense; 4316 4317 PetscFunctionBegin; 4318 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); 4319 PetscCall(MatSetSizes(C, m, n, m, n)); 4320 PetscCall(MatSetBlockSizesFromMats(C, A, B)); 4321 PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATSEQDENSECUDA, MATSEQDENSEHIP, "")); 4322 if (!cisdense) PetscCall(MatSetType(C, MATDENSE)); 4323 PetscCall(MatSetUp(C)); 4324 4325 C->ops->matmultnumeric = MatMatMultNumeric_SeqDense_SeqAIJ; 4326 PetscFunctionReturn(PETSC_SUCCESS); 4327 } 4328 4329 /*MC 4330 MATSEQAIJ - MATSEQAIJ = "seqaij" - A matrix type to be used for sequential sparse matrices, 4331 based on compressed sparse row format. 4332 4333 Options Database Key: 4334 . -mat_type seqaij - sets the matrix type to "seqaij" during a call to MatSetFromOptions() 4335 4336 Level: beginner 4337 4338 Notes: 4339 `MatSetValues()` may be called for this matrix type with a `NULL` argument for the numerical values, 4340 in this case the values associated with the rows and columns one passes in are set to zero 4341 in the matrix 4342 4343 `MatSetOptions`(,`MAT_STRUCTURE_ONLY`,`PETSC_TRUE`) may be called for this matrix type. In this no 4344 space is allocated for the nonzero entries and any entries passed with `MatSetValues()` are ignored 4345 4346 Developer Note: 4347 It would be nice if all matrix formats supported passing `NULL` in for the numerical values 4348 4349 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MatSetFromOptions()`, `MatSetType()`, `MatCreate()`, `MatType`, `MATSELL`, `MATSEQSELL`, `MATMPISELL` 4350 M*/ 4351 4352 /*MC 4353 MATAIJ - MATAIJ = "aij" - A matrix type to be used for sparse matrices. 4354 4355 This matrix type is identical to `MATSEQAIJ` when constructed with a single process communicator, 4356 and `MATMPIAIJ` otherwise. As a result, for single process communicators, 4357 `MatSeqAIJSetPreallocation()` is supported, and similarly `MatMPIAIJSetPreallocation()` is supported 4358 for communicators controlling multiple processes. It is recommended that you call both of 4359 the above preallocation routines for simplicity. 4360 4361 Options Database Key: 4362 . -mat_type aij - sets the matrix type to "aij" during a call to `MatSetFromOptions()` 4363 4364 Level: beginner 4365 4366 Note: 4367 Subclasses include `MATAIJCUSPARSE`, `MATAIJPERM`, `MATAIJSELL`, `MATAIJMKL`, `MATAIJCRL`, and also automatically switches over to use inodes when 4368 enough exist. 4369 4370 .seealso: [](ch_matrices), `Mat`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MATMPIAIJ`, `MATSELL`, `MATSEQSELL`, `MATMPISELL` 4371 M*/ 4372 4373 /*MC 4374 MATAIJCRL - MATAIJCRL = "aijcrl" - A matrix type to be used for sparse matrices. 4375 4376 Options Database Key: 4377 . -mat_type aijcrl - sets the matrix type to "aijcrl" during a call to `MatSetFromOptions()` 4378 4379 Level: beginner 4380 4381 Note: 4382 This matrix type is identical to `MATSEQAIJCRL` when constructed with a single process communicator, 4383 and `MATMPIAIJCRL` otherwise. As a result, for single process communicators, 4384 `MatSeqAIJSetPreallocation()` is supported, and similarly `MatMPIAIJSetPreallocation()` is supported 4385 for communicators controlling multiple processes. It is recommended that you call both of 4386 the above preallocation routines for simplicity. 4387 4388 .seealso: [](ch_matrices), `Mat`, `MatCreateMPIAIJCRL`, `MATSEQAIJCRL`, `MATMPIAIJCRL`, `MATSEQAIJCRL`, `MATMPIAIJCRL` 4389 M*/ 4390 4391 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJCRL(Mat, MatType, MatReuse, Mat *); 4392 #if defined(PETSC_HAVE_ELEMENTAL) 4393 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_Elemental(Mat, MatType, MatReuse, Mat *); 4394 #endif 4395 #if defined(PETSC_HAVE_SCALAPACK) 4396 PETSC_INTERN PetscErrorCode MatConvert_AIJ_ScaLAPACK(Mat, MatType, MatReuse, Mat *); 4397 #endif 4398 #if defined(PETSC_HAVE_HYPRE) 4399 PETSC_INTERN PetscErrorCode MatConvert_AIJ_HYPRE(Mat A, MatType, MatReuse, Mat *); 4400 #endif 4401 4402 PETSC_EXTERN PetscErrorCode MatConvert_SeqAIJ_SeqSELL(Mat, MatType, MatReuse, Mat *); 4403 PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat, MatType, MatReuse, Mat *); 4404 PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat); 4405 4406 /*@C 4407 MatSeqAIJGetArray - gives read/write access to the array where the data for a `MATSEQAIJ` matrix is stored 4408 4409 Not Collective 4410 4411 Input Parameter: 4412 . A - a `MATSEQAIJ` matrix 4413 4414 Output Parameter: 4415 . array - pointer to the data 4416 4417 Level: intermediate 4418 4419 Fortran Notes: 4420 `MatSeqAIJGetArray()` Fortran binding is deprecated (since PETSc 3.19), use `MatSeqAIJGetArrayF90()` 4421 4422 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJRestoreArray()`, `MatSeqAIJGetArrayF90()` 4423 @*/ 4424 PetscErrorCode MatSeqAIJGetArray(Mat A, PetscScalar *array[]) 4425 { 4426 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4427 4428 PetscFunctionBegin; 4429 if (aij->ops->getarray) { 4430 PetscCall((*aij->ops->getarray)(A, array)); 4431 } else { 4432 *array = aij->a; 4433 } 4434 PetscFunctionReturn(PETSC_SUCCESS); 4435 } 4436 4437 /*@C 4438 MatSeqAIJRestoreArray - returns access to the array where the data for a `MATSEQAIJ` matrix is stored obtained by `MatSeqAIJGetArray()` 4439 4440 Not Collective 4441 4442 Input Parameters: 4443 + A - a `MATSEQAIJ` matrix 4444 - array - pointer to the data 4445 4446 Level: intermediate 4447 4448 Fortran Notes: 4449 `MatSeqAIJRestoreArray()` Fortran binding is deprecated (since PETSc 3.19), use `MatSeqAIJRestoreArrayF90()` 4450 4451 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayF90()` 4452 @*/ 4453 PetscErrorCode MatSeqAIJRestoreArray(Mat A, PetscScalar *array[]) 4454 { 4455 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4456 4457 PetscFunctionBegin; 4458 if (aij->ops->restorearray) { 4459 PetscCall((*aij->ops->restorearray)(A, array)); 4460 } else { 4461 *array = NULL; 4462 } 4463 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 4464 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 4465 PetscFunctionReturn(PETSC_SUCCESS); 4466 } 4467 4468 /*@C 4469 MatSeqAIJGetArrayRead - gives read-only access to the array where the data for a `MATSEQAIJ` matrix is stored 4470 4471 Not Collective; No Fortran Support 4472 4473 Input Parameter: 4474 . A - a `MATSEQAIJ` matrix 4475 4476 Output Parameter: 4477 . array - pointer to the data 4478 4479 Level: intermediate 4480 4481 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayRead()` 4482 @*/ 4483 PetscErrorCode MatSeqAIJGetArrayRead(Mat A, const PetscScalar *array[]) 4484 { 4485 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4486 4487 PetscFunctionBegin; 4488 if (aij->ops->getarrayread) { 4489 PetscCall((*aij->ops->getarrayread)(A, array)); 4490 } else { 4491 *array = aij->a; 4492 } 4493 PetscFunctionReturn(PETSC_SUCCESS); 4494 } 4495 4496 /*@C 4497 MatSeqAIJRestoreArrayRead - restore the read-only access array obtained from `MatSeqAIJGetArrayRead()` 4498 4499 Not Collective; No Fortran Support 4500 4501 Input Parameter: 4502 . A - a `MATSEQAIJ` matrix 4503 4504 Output Parameter: 4505 . array - pointer to the data 4506 4507 Level: intermediate 4508 4509 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4510 @*/ 4511 PetscErrorCode MatSeqAIJRestoreArrayRead(Mat A, const PetscScalar *array[]) 4512 { 4513 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4514 4515 PetscFunctionBegin; 4516 if (aij->ops->restorearrayread) { 4517 PetscCall((*aij->ops->restorearrayread)(A, array)); 4518 } else { 4519 *array = NULL; 4520 } 4521 PetscFunctionReturn(PETSC_SUCCESS); 4522 } 4523 4524 /*@C 4525 MatSeqAIJGetArrayWrite - gives write-only access to the array where the data for a `MATSEQAIJ` matrix is stored 4526 4527 Not Collective; No Fortran Support 4528 4529 Input Parameter: 4530 . A - a `MATSEQAIJ` matrix 4531 4532 Output Parameter: 4533 . array - pointer to the data 4534 4535 Level: intermediate 4536 4537 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayRead()` 4538 @*/ 4539 PetscErrorCode MatSeqAIJGetArrayWrite(Mat A, PetscScalar *array[]) 4540 { 4541 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4542 4543 PetscFunctionBegin; 4544 if (aij->ops->getarraywrite) { 4545 PetscCall((*aij->ops->getarraywrite)(A, array)); 4546 } else { 4547 *array = aij->a; 4548 } 4549 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 4550 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 4551 PetscFunctionReturn(PETSC_SUCCESS); 4552 } 4553 4554 /*@C 4555 MatSeqAIJRestoreArrayWrite - restore the read-only access array obtained from MatSeqAIJGetArrayRead 4556 4557 Not Collective; No Fortran Support 4558 4559 Input Parameter: 4560 . A - a MATSEQAIJ matrix 4561 4562 Output Parameter: 4563 . array - pointer to the data 4564 4565 Level: intermediate 4566 4567 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4568 @*/ 4569 PetscErrorCode MatSeqAIJRestoreArrayWrite(Mat A, PetscScalar *array[]) 4570 { 4571 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4572 4573 PetscFunctionBegin; 4574 if (aij->ops->restorearraywrite) { 4575 PetscCall((*aij->ops->restorearraywrite)(A, array)); 4576 } else { 4577 *array = NULL; 4578 } 4579 PetscFunctionReturn(PETSC_SUCCESS); 4580 } 4581 4582 /*@C 4583 MatSeqAIJGetCSRAndMemType - Get the CSR arrays and the memory type of the `MATSEQAIJ` matrix 4584 4585 Not Collective; No Fortran Support 4586 4587 Input Parameter: 4588 . mat - a matrix of type `MATSEQAIJ` or its subclasses 4589 4590 Output Parameters: 4591 + i - row map array of the matrix 4592 . j - column index array of the matrix 4593 . a - data array of the matrix 4594 - mtype - memory type of the arrays 4595 4596 Level: developer 4597 4598 Notes: 4599 Any of the output parameters can be `NULL`, in which case the corresponding value is not returned. 4600 If mat is a device matrix, the arrays are on the device. Otherwise, they are on the host. 4601 4602 One can call this routine on a preallocated but not assembled matrix to just get the memory of the CSR underneath the matrix. 4603 If the matrix is assembled, the data array `a` is guaranteed to have the latest values of the matrix. 4604 4605 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4606 @*/ 4607 PetscErrorCode MatSeqAIJGetCSRAndMemType(Mat mat, const PetscInt *i[], const PetscInt *j[], PetscScalar *a[], PetscMemType *mtype) 4608 { 4609 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 4610 4611 PetscFunctionBegin; 4612 PetscCheck(mat->preallocated, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "matrix is not preallocated"); 4613 if (aij->ops->getcsrandmemtype) { 4614 PetscCall((*aij->ops->getcsrandmemtype)(mat, i, j, a, mtype)); 4615 } else { 4616 if (i) *i = aij->i; 4617 if (j) *j = aij->j; 4618 if (a) *a = aij->a; 4619 if (mtype) *mtype = PETSC_MEMTYPE_HOST; 4620 } 4621 PetscFunctionReturn(PETSC_SUCCESS); 4622 } 4623 4624 /*@ 4625 MatSeqAIJGetMaxRowNonzeros - returns the maximum number of nonzeros in any row 4626 4627 Not Collective 4628 4629 Input Parameter: 4630 . A - a `MATSEQAIJ` matrix 4631 4632 Output Parameter: 4633 . nz - the maximum number of nonzeros in any row 4634 4635 Level: intermediate 4636 4637 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJRestoreArray()`, `MatSeqAIJGetArrayF90()` 4638 @*/ 4639 PetscErrorCode MatSeqAIJGetMaxRowNonzeros(Mat A, PetscInt *nz) 4640 { 4641 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4642 4643 PetscFunctionBegin; 4644 *nz = aij->rmax; 4645 PetscFunctionReturn(PETSC_SUCCESS); 4646 } 4647 4648 static PetscErrorCode MatCOOStructDestroy_SeqAIJ(void **data) 4649 { 4650 MatCOOStruct_SeqAIJ *coo = (MatCOOStruct_SeqAIJ *)*data; 4651 4652 PetscFunctionBegin; 4653 PetscCall(PetscFree(coo->perm)); 4654 PetscCall(PetscFree(coo->jmap)); 4655 PetscCall(PetscFree(coo)); 4656 PetscFunctionReturn(PETSC_SUCCESS); 4657 } 4658 4659 PetscErrorCode MatSetPreallocationCOO_SeqAIJ(Mat mat, PetscCount coo_n, PetscInt coo_i[], PetscInt coo_j[]) 4660 { 4661 MPI_Comm comm; 4662 PetscInt *i, *j; 4663 PetscInt M, N, row, iprev; 4664 PetscCount k, p, q, nneg, nnz, start, end; /* Index the coo array, so use PetscCount as their type */ 4665 PetscInt *Ai; /* Change to PetscCount once we use it for row pointers */ 4666 PetscInt *Aj; 4667 PetscScalar *Aa; 4668 Mat_SeqAIJ *seqaij = (Mat_SeqAIJ *)mat->data; 4669 MatType rtype; 4670 PetscCount *perm, *jmap; 4671 MatCOOStruct_SeqAIJ *coo; 4672 PetscBool isorted; 4673 PetscBool hypre; 4674 const char *name; 4675 4676 PetscFunctionBegin; 4677 PetscCall(PetscObjectGetComm((PetscObject)mat, &comm)); 4678 PetscCall(MatGetSize(mat, &M, &N)); 4679 i = coo_i; 4680 j = coo_j; 4681 PetscCall(PetscMalloc1(coo_n, &perm)); 4682 4683 /* 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) */ 4684 isorted = PETSC_TRUE; 4685 iprev = PETSC_INT_MIN; 4686 for (k = 0; k < coo_n; k++) { 4687 if (j[k] < 0) i[k] = -1; 4688 if (isorted) { 4689 if (i[k] < iprev) isorted = PETSC_FALSE; 4690 else iprev = i[k]; 4691 } 4692 perm[k] = k; 4693 } 4694 4695 /* Sort by row if not already */ 4696 if (!isorted) PetscCall(PetscSortIntWithIntCountArrayPair(coo_n, i, j, perm)); 4697 4698 /* Advance k to the first row with a non-negative index */ 4699 for (k = 0; k < coo_n; k++) 4700 if (i[k] >= 0) break; 4701 nneg = k; 4702 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 */ 4703 nnz = 0; /* Total number of unique nonzeros to be counted */ 4704 jmap++; /* Inc jmap by 1 for convenience */ 4705 4706 PetscCall(PetscShmgetAllocateArray(M + 1, sizeof(PetscInt), (void **)&Ai)); /* CSR of A */ 4707 PetscCall(PetscArrayzero(Ai, M + 1)); 4708 PetscCall(PetscShmgetAllocateArray(coo_n - nneg, sizeof(PetscInt), (void **)&Aj)); /* We have at most coo_n-nneg unique nonzeros */ 4709 4710 PetscCall(PetscObjectGetName((PetscObject)mat, &name)); 4711 PetscCall(PetscStrcmp("_internal_COO_mat_for_hypre", name, &hypre)); 4712 4713 /* In each row, sort by column, then unique column indices to get row length */ 4714 Ai++; /* Inc by 1 for convenience */ 4715 q = 0; /* q-th unique nonzero, with q starting from 0 */ 4716 while (k < coo_n) { 4717 PetscBool strictly_sorted; // this row is strictly sorted? 4718 PetscInt jprev; 4719 4720 /* get [start,end) indices for this row; also check if cols in this row are strictly sorted */ 4721 row = i[k]; 4722 start = k; 4723 jprev = PETSC_INT_MIN; 4724 strictly_sorted = PETSC_TRUE; 4725 while (k < coo_n && i[k] == row) { 4726 if (strictly_sorted) { 4727 if (j[k] <= jprev) strictly_sorted = PETSC_FALSE; 4728 else jprev = j[k]; 4729 } 4730 k++; 4731 } 4732 end = k; 4733 4734 /* hack for HYPRE: swap min column to diag so that diagonal values will go first */ 4735 if (hypre) { 4736 PetscInt minj = PETSC_INT_MAX; 4737 PetscBool hasdiag = PETSC_FALSE; 4738 4739 if (strictly_sorted) { // fast path to swap the first and the diag 4740 PetscCount tmp; 4741 for (p = start; p < end; p++) { 4742 if (j[p] == row && p != start) { 4743 j[p] = j[start]; // swap j[], so that the diagonal value will go first (manipulated by perm[]) 4744 j[start] = row; 4745 tmp = perm[start]; 4746 perm[start] = perm[p]; // also swap perm[] so we can save the call to PetscSortIntWithCountArray() below 4747 perm[p] = tmp; 4748 break; 4749 } 4750 } 4751 } else { 4752 for (p = start; p < end; p++) { 4753 hasdiag = (PetscBool)(hasdiag || (j[p] == row)); 4754 minj = PetscMin(minj, j[p]); 4755 } 4756 4757 if (hasdiag) { 4758 for (p = start; p < end; p++) { 4759 if (j[p] == minj) j[p] = row; 4760 else if (j[p] == row) j[p] = minj; 4761 } 4762 } 4763 } 4764 } 4765 // sort by columns in a row. perm[] indicates their original order 4766 if (!strictly_sorted) PetscCall(PetscSortIntWithCountArray(end - start, j + start, perm + start)); 4767 4768 if (strictly_sorted) { // fast path to set Aj[], jmap[], Ai[], nnz, q 4769 for (p = start; p < end; p++, q++) { 4770 Aj[q] = j[p]; 4771 jmap[q] = 1; 4772 } 4773 PetscCall(PetscIntCast(end - start, Ai + row)); 4774 nnz += Ai[row]; // q is already advanced 4775 } else { 4776 /* Find number of unique col entries in this row */ 4777 Aj[q] = j[start]; /* Log the first nonzero in this row */ 4778 jmap[q] = 1; /* Number of repeats of this nonzero entry */ 4779 Ai[row] = 1; 4780 nnz++; 4781 4782 for (p = start + 1; p < end; p++) { /* Scan remaining nonzero in this row */ 4783 if (j[p] != j[p - 1]) { /* Meet a new nonzero */ 4784 q++; 4785 jmap[q] = 1; 4786 Aj[q] = j[p]; 4787 Ai[row]++; 4788 nnz++; 4789 } else { 4790 jmap[q]++; 4791 } 4792 } 4793 q++; /* Move to next row and thus next unique nonzero */ 4794 } 4795 } 4796 4797 Ai--; /* Back to the beginning of Ai[] */ 4798 for (k = 0; k < M; k++) Ai[k + 1] += Ai[k]; 4799 jmap--; // Back to the beginning of jmap[] 4800 jmap[0] = 0; 4801 for (k = 0; k < nnz; k++) jmap[k + 1] += jmap[k]; 4802 4803 if (nnz < coo_n - nneg) { /* Reallocate with actual number of unique nonzeros */ 4804 PetscCount *jmap_new; 4805 PetscInt *Aj_new; 4806 4807 PetscCall(PetscMalloc1(nnz + 1, &jmap_new)); 4808 PetscCall(PetscArraycpy(jmap_new, jmap, nnz + 1)); 4809 PetscCall(PetscFree(jmap)); 4810 jmap = jmap_new; 4811 4812 PetscCall(PetscShmgetAllocateArray(nnz, sizeof(PetscInt), (void **)&Aj_new)); 4813 PetscCall(PetscArraycpy(Aj_new, Aj, nnz)); 4814 PetscCall(PetscShmgetDeallocateArray((void **)&Aj)); 4815 Aj = Aj_new; 4816 } 4817 4818 if (nneg) { /* Discard heading entries with negative indices in perm[], as we'll access it from index 0 in MatSetValuesCOO */ 4819 PetscCount *perm_new; 4820 4821 PetscCall(PetscMalloc1(coo_n - nneg, &perm_new)); 4822 PetscCall(PetscArraycpy(perm_new, perm + nneg, coo_n - nneg)); 4823 PetscCall(PetscFree(perm)); 4824 perm = perm_new; 4825 } 4826 4827 PetscCall(MatGetRootType_Private(mat, &rtype)); 4828 PetscCall(PetscShmgetAllocateArray(nnz, sizeof(PetscScalar), (void **)&Aa)); 4829 PetscCall(PetscArrayzero(Aa, nnz)); 4830 PetscCall(MatSetSeqAIJWithArrays_private(PETSC_COMM_SELF, M, N, Ai, Aj, Aa, rtype, mat)); 4831 4832 seqaij->free_a = seqaij->free_ij = PETSC_TRUE; /* Let newmat own Ai, Aj and Aa */ 4833 4834 // Put the COO struct in a container and then attach that to the matrix 4835 PetscCall(PetscMalloc1(1, &coo)); 4836 PetscCall(PetscIntCast(nnz, &coo->nz)); 4837 coo->n = coo_n; 4838 coo->Atot = coo_n - nneg; // Annz is seqaij->nz, so no need to record that again 4839 coo->jmap = jmap; // of length nnz+1 4840 coo->perm = perm; 4841 PetscCall(PetscObjectContainerCompose((PetscObject)mat, "__PETSc_MatCOOStruct_Host", coo, MatCOOStructDestroy_SeqAIJ)); 4842 PetscFunctionReturn(PETSC_SUCCESS); 4843 } 4844 4845 static PetscErrorCode MatSetValuesCOO_SeqAIJ(Mat A, const PetscScalar v[], InsertMode imode) 4846 { 4847 Mat_SeqAIJ *aseq = (Mat_SeqAIJ *)A->data; 4848 PetscCount i, j, Annz = aseq->nz; 4849 PetscCount *perm, *jmap; 4850 PetscScalar *Aa; 4851 PetscContainer container; 4852 MatCOOStruct_SeqAIJ *coo; 4853 4854 PetscFunctionBegin; 4855 PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_MatCOOStruct_Host", (PetscObject *)&container)); 4856 PetscCheck(container, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not found MatCOOStruct on this matrix"); 4857 PetscCall(PetscContainerGetPointer(container, (void **)&coo)); 4858 perm = coo->perm; 4859 jmap = coo->jmap; 4860 PetscCall(MatSeqAIJGetArray(A, &Aa)); 4861 for (i = 0; i < Annz; i++) { 4862 PetscScalar sum = 0.0; 4863 for (j = jmap[i]; j < jmap[i + 1]; j++) sum += v[perm[j]]; 4864 Aa[i] = (imode == INSERT_VALUES ? 0.0 : Aa[i]) + sum; 4865 } 4866 PetscCall(MatSeqAIJRestoreArray(A, &Aa)); 4867 PetscFunctionReturn(PETSC_SUCCESS); 4868 } 4869 4870 #if defined(PETSC_HAVE_CUDA) 4871 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJCUSPARSE(Mat, MatType, MatReuse, Mat *); 4872 #endif 4873 #if defined(PETSC_HAVE_HIP) 4874 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJHIPSPARSE(Mat, MatType, MatReuse, Mat *); 4875 #endif 4876 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 4877 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJKokkos(Mat, MatType, MatReuse, Mat *); 4878 #endif 4879 4880 PETSC_EXTERN PetscErrorCode MatCreate_SeqAIJ(Mat B) 4881 { 4882 Mat_SeqAIJ *b; 4883 PetscMPIInt size; 4884 4885 PetscFunctionBegin; 4886 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)B), &size)); 4887 PetscCheck(size <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Comm must be of size 1"); 4888 4889 PetscCall(PetscNew(&b)); 4890 4891 B->data = (void *)b; 4892 B->ops[0] = MatOps_Values; 4893 if (B->sortedfull) B->ops->setvalues = MatSetValues_SeqAIJ_SortedFull; 4894 4895 b->row = NULL; 4896 b->col = NULL; 4897 b->icol = NULL; 4898 b->reallocs = 0; 4899 b->ignorezeroentries = PETSC_FALSE; 4900 b->roworiented = PETSC_TRUE; 4901 b->nonew = 0; 4902 b->diag = NULL; 4903 b->solve_work = NULL; 4904 B->spptr = NULL; 4905 b->saved_values = NULL; 4906 b->idiag = NULL; 4907 b->mdiag = NULL; 4908 b->ssor_work = NULL; 4909 b->omega = 1.0; 4910 b->fshift = 0.0; 4911 b->idiagvalid = PETSC_FALSE; 4912 b->ibdiagvalid = PETSC_FALSE; 4913 b->keepnonzeropattern = PETSC_FALSE; 4914 4915 PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATSEQAIJ)); 4916 #if defined(PETSC_HAVE_MATLAB) 4917 PetscCall(PetscObjectComposeFunction((PetscObject)B, "PetscMatlabEnginePut_C", MatlabEnginePut_SeqAIJ)); 4918 PetscCall(PetscObjectComposeFunction((PetscObject)B, "PetscMatlabEngineGet_C", MatlabEngineGet_SeqAIJ)); 4919 #endif 4920 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetColumnIndices_C", MatSeqAIJSetColumnIndices_SeqAIJ)); 4921 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatStoreValues_C", MatStoreValues_SeqAIJ)); 4922 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatRetrieveValues_C", MatRetrieveValues_SeqAIJ)); 4923 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqsbaij_C", MatConvert_SeqAIJ_SeqSBAIJ)); 4924 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqbaij_C", MatConvert_SeqAIJ_SeqBAIJ)); 4925 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijperm_C", MatConvert_SeqAIJ_SeqAIJPERM)); 4926 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijsell_C", MatConvert_SeqAIJ_SeqAIJSELL)); 4927 #if defined(PETSC_HAVE_MKL_SPARSE) 4928 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijmkl_C", MatConvert_SeqAIJ_SeqAIJMKL)); 4929 #endif 4930 #if defined(PETSC_HAVE_CUDA) 4931 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijcusparse_C", MatConvert_SeqAIJ_SeqAIJCUSPARSE)); 4932 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaijcusparse_seqaij_C", MatProductSetFromOptions_SeqAIJ)); 4933 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaijcusparse_C", MatProductSetFromOptions_SeqAIJ)); 4934 #endif 4935 #if defined(PETSC_HAVE_HIP) 4936 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijhipsparse_C", MatConvert_SeqAIJ_SeqAIJHIPSPARSE)); 4937 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaijhipsparse_seqaij_C", MatProductSetFromOptions_SeqAIJ)); 4938 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaijhipsparse_C", MatProductSetFromOptions_SeqAIJ)); 4939 #endif 4940 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 4941 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijkokkos_C", MatConvert_SeqAIJ_SeqAIJKokkos)); 4942 #endif 4943 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijcrl_C", MatConvert_SeqAIJ_SeqAIJCRL)); 4944 #if defined(PETSC_HAVE_ELEMENTAL) 4945 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_elemental_C", MatConvert_SeqAIJ_Elemental)); 4946 #endif 4947 #if defined(PETSC_HAVE_SCALAPACK) 4948 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_scalapack_C", MatConvert_AIJ_ScaLAPACK)); 4949 #endif 4950 #if defined(PETSC_HAVE_HYPRE) 4951 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_hypre_C", MatConvert_AIJ_HYPRE)); 4952 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_transpose_seqaij_seqaij_C", MatProductSetFromOptions_Transpose_AIJ_AIJ)); 4953 #endif 4954 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqdense_C", MatConvert_SeqAIJ_SeqDense)); 4955 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqsell_C", MatConvert_SeqAIJ_SeqSELL)); 4956 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_is_C", MatConvert_XAIJ_IS)); 4957 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsTranspose_C", MatIsTranspose_SeqAIJ)); 4958 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsHermitianTranspose_C", MatIsHermitianTranspose_SeqAIJ)); 4959 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetPreallocation_C", MatSeqAIJSetPreallocation_SeqAIJ)); 4960 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatResetPreallocation_C", MatResetPreallocation_SeqAIJ)); 4961 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatResetHash_C", MatResetHash_SeqAIJ)); 4962 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetPreallocationCSR_C", MatSeqAIJSetPreallocationCSR_SeqAIJ)); 4963 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatReorderForNonzeroDiagonal_C", MatReorderForNonzeroDiagonal_SeqAIJ)); 4964 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_is_seqaij_C", MatProductSetFromOptions_IS_XAIJ)); 4965 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqdense_seqaij_C", MatProductSetFromOptions_SeqDense_SeqAIJ)); 4966 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaij_C", MatProductSetFromOptions_SeqAIJ)); 4967 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJKron_C", MatSeqAIJKron_SeqAIJ)); 4968 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_SeqAIJ)); 4969 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSetValuesCOO_C", MatSetValuesCOO_SeqAIJ)); 4970 PetscCall(MatCreate_SeqAIJ_Inode(B)); 4971 PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATSEQAIJ)); 4972 PetscCall(MatSeqAIJSetTypeFromOptions(B)); /* this allows changing the matrix subtype to say MATSEQAIJPERM */ 4973 PetscFunctionReturn(PETSC_SUCCESS); 4974 } 4975 4976 /* 4977 Given a matrix generated with MatGetFactor() duplicates all the information in A into C 4978 */ 4979 PetscErrorCode MatDuplicateNoCreate_SeqAIJ(Mat C, Mat A, MatDuplicateOption cpvalues, PetscBool mallocmatspace) 4980 { 4981 Mat_SeqAIJ *c = (Mat_SeqAIJ *)C->data, *a = (Mat_SeqAIJ *)A->data; 4982 PetscInt m = A->rmap->n, i; 4983 4984 PetscFunctionBegin; 4985 PetscCheck(A->assembled || cpvalues == MAT_DO_NOT_COPY_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot duplicate unassembled matrix"); 4986 4987 C->factortype = A->factortype; 4988 c->row = NULL; 4989 c->col = NULL; 4990 c->icol = NULL; 4991 c->reallocs = 0; 4992 c->diagonaldense = a->diagonaldense; 4993 4994 C->assembled = A->assembled; 4995 4996 if (A->preallocated) { 4997 PetscCall(PetscLayoutReference(A->rmap, &C->rmap)); 4998 PetscCall(PetscLayoutReference(A->cmap, &C->cmap)); 4999 5000 if (!A->hash_active) { 5001 PetscCall(PetscMalloc1(m, &c->imax)); 5002 PetscCall(PetscMemcpy(c->imax, a->imax, m * sizeof(PetscInt))); 5003 PetscCall(PetscMalloc1(m, &c->ilen)); 5004 PetscCall(PetscMemcpy(c->ilen, a->ilen, m * sizeof(PetscInt))); 5005 5006 /* allocate the matrix space */ 5007 if (mallocmatspace) { 5008 PetscCall(PetscShmgetAllocateArray(a->i[m], sizeof(PetscScalar), (void **)&c->a)); 5009 PetscCall(PetscShmgetAllocateArray(a->i[m], sizeof(PetscInt), (void **)&c->j)); 5010 PetscCall(PetscShmgetAllocateArray(m + 1, sizeof(PetscInt), (void **)&c->i)); 5011 PetscCall(PetscArraycpy(c->i, a->i, m + 1)); 5012 c->free_a = PETSC_TRUE; 5013 c->free_ij = PETSC_TRUE; 5014 if (m > 0) { 5015 PetscCall(PetscArraycpy(c->j, a->j, a->i[m])); 5016 if (cpvalues == MAT_COPY_VALUES) { 5017 const PetscScalar *aa; 5018 5019 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 5020 PetscCall(PetscArraycpy(c->a, aa, a->i[m])); 5021 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 5022 } else { 5023 PetscCall(PetscArrayzero(c->a, a->i[m])); 5024 } 5025 } 5026 } 5027 C->preallocated = PETSC_TRUE; 5028 } else { 5029 PetscCheck(mallocmatspace, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Cannot malloc matrix memory from a non-preallocated matrix"); 5030 PetscCall(MatSetUp(C)); 5031 } 5032 5033 c->ignorezeroentries = a->ignorezeroentries; 5034 c->roworiented = a->roworiented; 5035 c->nonew = a->nonew; 5036 if (a->diag) { 5037 PetscCall(PetscMalloc1(m + 1, &c->diag)); 5038 PetscCall(PetscMemcpy(c->diag, a->diag, m * sizeof(PetscInt))); 5039 } else c->diag = NULL; 5040 5041 c->solve_work = NULL; 5042 c->saved_values = NULL; 5043 c->idiag = NULL; 5044 c->ssor_work = NULL; 5045 c->keepnonzeropattern = a->keepnonzeropattern; 5046 5047 c->rmax = a->rmax; 5048 c->nz = a->nz; 5049 c->maxnz = a->nz; /* Since we allocate exactly the right amount */ 5050 5051 c->compressedrow.use = a->compressedrow.use; 5052 c->compressedrow.nrows = a->compressedrow.nrows; 5053 if (a->compressedrow.use) { 5054 i = a->compressedrow.nrows; 5055 PetscCall(PetscMalloc2(i + 1, &c->compressedrow.i, i, &c->compressedrow.rindex)); 5056 PetscCall(PetscArraycpy(c->compressedrow.i, a->compressedrow.i, i + 1)); 5057 PetscCall(PetscArraycpy(c->compressedrow.rindex, a->compressedrow.rindex, i)); 5058 } else { 5059 c->compressedrow.use = PETSC_FALSE; 5060 c->compressedrow.i = NULL; 5061 c->compressedrow.rindex = NULL; 5062 } 5063 c->nonzerorowcnt = a->nonzerorowcnt; 5064 C->nonzerostate = A->nonzerostate; 5065 5066 PetscCall(MatDuplicate_SeqAIJ_Inode(A, cpvalues, &C)); 5067 } 5068 PetscCall(PetscFunctionListDuplicate(((PetscObject)A)->qlist, &((PetscObject)C)->qlist)); 5069 PetscFunctionReturn(PETSC_SUCCESS); 5070 } 5071 5072 PetscErrorCode MatDuplicate_SeqAIJ(Mat A, MatDuplicateOption cpvalues, Mat *B) 5073 { 5074 PetscFunctionBegin; 5075 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B)); 5076 PetscCall(MatSetSizes(*B, A->rmap->n, A->cmap->n, A->rmap->n, A->cmap->n)); 5077 if (!(A->rmap->n % A->rmap->bs) && !(A->cmap->n % A->cmap->bs)) PetscCall(MatSetBlockSizesFromMats(*B, A, A)); 5078 PetscCall(MatSetType(*B, ((PetscObject)A)->type_name)); 5079 PetscCall(MatDuplicateNoCreate_SeqAIJ(*B, A, cpvalues, PETSC_TRUE)); 5080 PetscFunctionReturn(PETSC_SUCCESS); 5081 } 5082 5083 PetscErrorCode MatLoad_SeqAIJ(Mat newMat, PetscViewer viewer) 5084 { 5085 PetscBool isbinary, ishdf5; 5086 5087 PetscFunctionBegin; 5088 PetscValidHeaderSpecific(newMat, MAT_CLASSID, 1); 5089 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 5090 /* force binary viewer to load .info file if it has not yet done so */ 5091 PetscCall(PetscViewerSetUp(viewer)); 5092 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 5093 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 5094 if (isbinary) { 5095 PetscCall(MatLoad_SeqAIJ_Binary(newMat, viewer)); 5096 } else if (ishdf5) { 5097 #if defined(PETSC_HAVE_HDF5) 5098 PetscCall(MatLoad_AIJ_HDF5(newMat, viewer)); 5099 #else 5100 SETERRQ(PetscObjectComm((PetscObject)newMat), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 5101 #endif 5102 } else { 5103 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); 5104 } 5105 PetscFunctionReturn(PETSC_SUCCESS); 5106 } 5107 5108 PetscErrorCode MatLoad_SeqAIJ_Binary(Mat mat, PetscViewer viewer) 5109 { 5110 Mat_SeqAIJ *a = (Mat_SeqAIJ *)mat->data; 5111 PetscInt header[4], *rowlens, M, N, nz, sum, rows, cols, i; 5112 5113 PetscFunctionBegin; 5114 PetscCall(PetscViewerSetUp(viewer)); 5115 5116 /* read in matrix header */ 5117 PetscCall(PetscViewerBinaryRead(viewer, header, 4, NULL, PETSC_INT)); 5118 PetscCheck(header[0] == MAT_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a matrix object in file"); 5119 M = header[1]; 5120 N = header[2]; 5121 nz = header[3]; 5122 PetscCheck(M >= 0, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Matrix row size (%" PetscInt_FMT ") in file is negative", M); 5123 PetscCheck(N >= 0, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Matrix column size (%" PetscInt_FMT ") in file is negative", N); 5124 PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Matrix stored in special format on disk, cannot load as SeqAIJ"); 5125 5126 /* set block sizes from the viewer's .info file */ 5127 PetscCall(MatLoad_Binary_BlockSizes(mat, viewer)); 5128 /* set local and global sizes if not set already */ 5129 if (mat->rmap->n < 0) mat->rmap->n = M; 5130 if (mat->cmap->n < 0) mat->cmap->n = N; 5131 if (mat->rmap->N < 0) mat->rmap->N = M; 5132 if (mat->cmap->N < 0) mat->cmap->N = N; 5133 PetscCall(PetscLayoutSetUp(mat->rmap)); 5134 PetscCall(PetscLayoutSetUp(mat->cmap)); 5135 5136 /* check if the matrix sizes are correct */ 5137 PetscCall(MatGetSize(mat, &rows, &cols)); 5138 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); 5139 5140 /* read in row lengths */ 5141 PetscCall(PetscMalloc1(M, &rowlens)); 5142 PetscCall(PetscViewerBinaryRead(viewer, rowlens, M, NULL, PETSC_INT)); 5143 /* check if sum(rowlens) is same as nz */ 5144 sum = 0; 5145 for (i = 0; i < M; i++) sum += rowlens[i]; 5146 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); 5147 /* preallocate and check sizes */ 5148 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(mat, 0, rowlens)); 5149 PetscCall(MatGetSize(mat, &rows, &cols)); 5150 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); 5151 /* store row lengths */ 5152 PetscCall(PetscArraycpy(a->ilen, rowlens, M)); 5153 PetscCall(PetscFree(rowlens)); 5154 5155 /* fill in "i" row pointers */ 5156 a->i[0] = 0; 5157 for (i = 0; i < M; i++) a->i[i + 1] = a->i[i] + a->ilen[i]; 5158 /* read in "j" column indices */ 5159 PetscCall(PetscViewerBinaryRead(viewer, a->j, nz, NULL, PETSC_INT)); 5160 /* read in "a" nonzero values */ 5161 PetscCall(PetscViewerBinaryRead(viewer, a->a, nz, NULL, PETSC_SCALAR)); 5162 5163 PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY)); 5164 PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY)); 5165 PetscFunctionReturn(PETSC_SUCCESS); 5166 } 5167 5168 PetscErrorCode MatEqual_SeqAIJ(Mat A, Mat B, PetscBool *flg) 5169 { 5170 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *b = (Mat_SeqAIJ *)B->data; 5171 const PetscScalar *aa, *ba; 5172 #if defined(PETSC_USE_COMPLEX) 5173 PetscInt k; 5174 #endif 5175 5176 PetscFunctionBegin; 5177 /* If the matrix dimensions are not equal,or no of nonzeros */ 5178 if ((A->rmap->n != B->rmap->n) || (A->cmap->n != B->cmap->n) || (a->nz != b->nz)) { 5179 *flg = PETSC_FALSE; 5180 PetscFunctionReturn(PETSC_SUCCESS); 5181 } 5182 5183 /* if the a->i are the same */ 5184 PetscCall(PetscArraycmp(a->i, b->i, A->rmap->n + 1, flg)); 5185 if (!*flg) PetscFunctionReturn(PETSC_SUCCESS); 5186 5187 /* if a->j are the same */ 5188 PetscCall(PetscArraycmp(a->j, b->j, a->nz, flg)); 5189 if (!*flg) PetscFunctionReturn(PETSC_SUCCESS); 5190 5191 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 5192 PetscCall(MatSeqAIJGetArrayRead(B, &ba)); 5193 /* if a->a are the same */ 5194 #if defined(PETSC_USE_COMPLEX) 5195 for (k = 0; k < a->nz; k++) { 5196 if (PetscRealPart(aa[k]) != PetscRealPart(ba[k]) || PetscImaginaryPart(aa[k]) != PetscImaginaryPart(ba[k])) { 5197 *flg = PETSC_FALSE; 5198 PetscFunctionReturn(PETSC_SUCCESS); 5199 } 5200 } 5201 #else 5202 PetscCall(PetscArraycmp(aa, ba, a->nz, flg)); 5203 #endif 5204 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 5205 PetscCall(MatSeqAIJRestoreArrayRead(B, &ba)); 5206 PetscFunctionReturn(PETSC_SUCCESS); 5207 } 5208 5209 /*@ 5210 MatCreateSeqAIJWithArrays - Creates an sequential `MATSEQAIJ` matrix using matrix elements (in CSR format) 5211 provided by the user. 5212 5213 Collective 5214 5215 Input Parameters: 5216 + comm - must be an MPI communicator of size 1 5217 . m - number of rows 5218 . n - number of columns 5219 . i - row indices; that is i[0] = 0, i[row] = i[row-1] + number of elements in that row of the matrix 5220 . j - column indices 5221 - a - matrix values 5222 5223 Output Parameter: 5224 . mat - the matrix 5225 5226 Level: intermediate 5227 5228 Notes: 5229 The `i`, `j`, and `a` arrays are not copied by this routine, the user must free these arrays 5230 once the matrix is destroyed and not before 5231 5232 You cannot set new nonzero locations into this matrix, that will generate an error. 5233 5234 The `i` and `j` indices are 0 based 5235 5236 The format which is used for the sparse matrix input, is equivalent to a 5237 row-major ordering.. i.e for the following matrix, the input data expected is 5238 as shown 5239 .vb 5240 1 0 0 5241 2 0 3 5242 4 5 6 5243 5244 i = {0,1,3,6} [size = nrow+1 = 3+1] 5245 j = {0,0,2,0,1,2} [size = 6]; values must be sorted for each row 5246 v = {1,2,3,4,5,6} [size = 6] 5247 .ve 5248 5249 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MatCreateMPIAIJWithArrays()`, `MatMPIAIJSetPreallocationCSR()` 5250 @*/ 5251 PetscErrorCode MatCreateSeqAIJWithArrays(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt i[], PetscInt j[], PetscScalar a[], Mat *mat) 5252 { 5253 PetscInt ii; 5254 Mat_SeqAIJ *aij; 5255 PetscInt jj; 5256 5257 PetscFunctionBegin; 5258 PetscCheck(m <= 0 || i[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "i (row indices) must start with 0"); 5259 PetscCall(MatCreate(comm, mat)); 5260 PetscCall(MatSetSizes(*mat, m, n, m, n)); 5261 /* PetscCall(MatSetBlockSizes(*mat,,)); */ 5262 PetscCall(MatSetType(*mat, MATSEQAIJ)); 5263 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*mat, MAT_SKIP_ALLOCATION, NULL)); 5264 aij = (Mat_SeqAIJ *)(*mat)->data; 5265 PetscCall(PetscMalloc1(m, &aij->imax)); 5266 PetscCall(PetscMalloc1(m, &aij->ilen)); 5267 5268 aij->i = i; 5269 aij->j = j; 5270 aij->a = a; 5271 aij->nonew = -1; /*this indicates that inserting a new value in the matrix that generates a new nonzero is an error*/ 5272 aij->free_a = PETSC_FALSE; 5273 aij->free_ij = PETSC_FALSE; 5274 5275 for (ii = 0, aij->nonzerorowcnt = 0, aij->rmax = 0; ii < m; ii++) { 5276 aij->ilen[ii] = aij->imax[ii] = i[ii + 1] - i[ii]; 5277 if (PetscDefined(USE_DEBUG)) { 5278 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]); 5279 for (jj = i[ii] + 1; jj < i[ii + 1]; jj++) { 5280 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); 5281 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); 5282 } 5283 } 5284 } 5285 if (PetscDefined(USE_DEBUG)) { 5286 for (ii = 0; ii < aij->i[m]; ii++) { 5287 PetscCheck(j[ii] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative column index at location = %" PetscInt_FMT " index = %" PetscInt_FMT, ii, j[ii]); 5288 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); 5289 } 5290 } 5291 5292 PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY)); 5293 PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY)); 5294 PetscFunctionReturn(PETSC_SUCCESS); 5295 } 5296 5297 /*@ 5298 MatCreateSeqAIJFromTriple - Creates an sequential `MATSEQAIJ` matrix using matrix elements (in COO format) 5299 provided by the user. 5300 5301 Collective 5302 5303 Input Parameters: 5304 + comm - must be an MPI communicator of size 1 5305 . m - number of rows 5306 . n - number of columns 5307 . i - row indices 5308 . j - column indices 5309 . a - matrix values 5310 . nz - number of nonzeros 5311 - idx - if the `i` and `j` indices start with 1 use `PETSC_TRUE` otherwise use `PETSC_FALSE` 5312 5313 Output Parameter: 5314 . mat - the matrix 5315 5316 Level: intermediate 5317 5318 Example: 5319 For the following matrix, the input data expected is as shown (using 0 based indexing) 5320 .vb 5321 1 0 0 5322 2 0 3 5323 4 5 6 5324 5325 i = {0,1,1,2,2,2} 5326 j = {0,0,2,0,1,2} 5327 v = {1,2,3,4,5,6} 5328 .ve 5329 5330 Note: 5331 Instead of using this function, users should also consider `MatSetPreallocationCOO()` and `MatSetValuesCOO()`, which allow repeated or remote entries, 5332 and are particularly useful in iterative applications. 5333 5334 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MatCreateSeqAIJWithArrays()`, `MatMPIAIJSetPreallocationCSR()`, `MatSetValuesCOO()`, `MatSetPreallocationCOO()` 5335 @*/ 5336 PetscErrorCode MatCreateSeqAIJFromTriple(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt i[], PetscInt j[], PetscScalar a[], Mat *mat, PetscInt nz, PetscBool idx) 5337 { 5338 PetscInt ii, *nnz, one = 1, row, col; 5339 5340 PetscFunctionBegin; 5341 PetscCall(PetscCalloc1(m, &nnz)); 5342 for (ii = 0; ii < nz; ii++) nnz[i[ii] - !!idx] += 1; 5343 PetscCall(MatCreate(comm, mat)); 5344 PetscCall(MatSetSizes(*mat, m, n, m, n)); 5345 PetscCall(MatSetType(*mat, MATSEQAIJ)); 5346 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*mat, 0, nnz)); 5347 for (ii = 0; ii < nz; ii++) { 5348 if (idx) { 5349 row = i[ii] - 1; 5350 col = j[ii] - 1; 5351 } else { 5352 row = i[ii]; 5353 col = j[ii]; 5354 } 5355 PetscCall(MatSetValues(*mat, one, &row, one, &col, &a[ii], ADD_VALUES)); 5356 } 5357 PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY)); 5358 PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY)); 5359 PetscCall(PetscFree(nnz)); 5360 PetscFunctionReturn(PETSC_SUCCESS); 5361 } 5362 5363 PetscErrorCode MatSeqAIJInvalidateDiagonal(Mat A) 5364 { 5365 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 5366 5367 PetscFunctionBegin; 5368 a->idiagvalid = PETSC_FALSE; 5369 a->ibdiagvalid = PETSC_FALSE; 5370 5371 PetscCall(MatSeqAIJInvalidateDiagonal_Inode(A)); 5372 PetscFunctionReturn(PETSC_SUCCESS); 5373 } 5374 5375 PetscErrorCode MatCreateMPIMatConcatenateSeqMat_SeqAIJ(MPI_Comm comm, Mat inmat, PetscInt n, MatReuse scall, Mat *outmat) 5376 { 5377 PetscFunctionBegin; 5378 PetscCall(MatCreateMPIMatConcatenateSeqMat_MPIAIJ(comm, inmat, n, scall, outmat)); 5379 PetscFunctionReturn(PETSC_SUCCESS); 5380 } 5381 5382 /* 5383 Permute A into C's *local* index space using rowemb,colemb. 5384 The embedding are supposed to be injections and the above implies that the range of rowemb is a subset 5385 of [0,m), colemb is in [0,n). 5386 If pattern == DIFFERENT_NONZERO_PATTERN, C is preallocated according to A. 5387 */ 5388 PetscErrorCode MatSetSeqMat_SeqAIJ(Mat C, IS rowemb, IS colemb, MatStructure pattern, Mat B) 5389 { 5390 /* If making this function public, change the error returned in this function away from _PLIB. */ 5391 Mat_SeqAIJ *Baij; 5392 PetscBool seqaij; 5393 PetscInt m, n, *nz, i, j, count; 5394 PetscScalar v; 5395 const PetscInt *rowindices, *colindices; 5396 5397 PetscFunctionBegin; 5398 if (!B) PetscFunctionReturn(PETSC_SUCCESS); 5399 /* Check to make sure the target matrix (and embeddings) are compatible with C and each other. */ 5400 PetscCall(PetscObjectBaseTypeCompare((PetscObject)B, MATSEQAIJ, &seqaij)); 5401 PetscCheck(seqaij, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is of wrong type"); 5402 if (rowemb) { 5403 PetscCall(ISGetLocalSize(rowemb, &m)); 5404 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); 5405 } else { 5406 PetscCheck(C->rmap->n == B->rmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is row-incompatible with the target matrix"); 5407 } 5408 if (colemb) { 5409 PetscCall(ISGetLocalSize(colemb, &n)); 5410 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); 5411 } else { 5412 PetscCheck(C->cmap->n == B->cmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is col-incompatible with the target matrix"); 5413 } 5414 5415 Baij = (Mat_SeqAIJ *)B->data; 5416 if (pattern == DIFFERENT_NONZERO_PATTERN) { 5417 PetscCall(PetscMalloc1(B->rmap->n, &nz)); 5418 for (i = 0; i < B->rmap->n; i++) nz[i] = Baij->i[i + 1] - Baij->i[i]; 5419 PetscCall(MatSeqAIJSetPreallocation(C, 0, nz)); 5420 PetscCall(PetscFree(nz)); 5421 } 5422 if (pattern == SUBSET_NONZERO_PATTERN) PetscCall(MatZeroEntries(C)); 5423 count = 0; 5424 rowindices = NULL; 5425 colindices = NULL; 5426 if (rowemb) PetscCall(ISGetIndices(rowemb, &rowindices)); 5427 if (colemb) PetscCall(ISGetIndices(colemb, &colindices)); 5428 for (i = 0; i < B->rmap->n; i++) { 5429 PetscInt row; 5430 row = i; 5431 if (rowindices) row = rowindices[i]; 5432 for (j = Baij->i[i]; j < Baij->i[i + 1]; j++) { 5433 PetscInt col; 5434 col = Baij->j[count]; 5435 if (colindices) col = colindices[col]; 5436 v = Baij->a[count]; 5437 PetscCall(MatSetValues(C, 1, &row, 1, &col, &v, INSERT_VALUES)); 5438 ++count; 5439 } 5440 } 5441 /* FIXME: set C's nonzerostate correctly. */ 5442 /* Assembly for C is necessary. */ 5443 C->preallocated = PETSC_TRUE; 5444 C->assembled = PETSC_TRUE; 5445 C->was_assembled = PETSC_FALSE; 5446 PetscFunctionReturn(PETSC_SUCCESS); 5447 } 5448 5449 PetscErrorCode MatEliminateZeros_SeqAIJ(Mat A, PetscBool keep) 5450 { 5451 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 5452 MatScalar *aa = a->a; 5453 PetscInt m = A->rmap->n, fshift = 0, fshift_prev = 0, i, k; 5454 PetscInt *ailen = a->ilen, *imax = a->imax, *ai = a->i, *aj = a->j, rmax = 0; 5455 5456 PetscFunctionBegin; 5457 PetscCheck(A->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot eliminate zeros for unassembled matrix"); 5458 if (m) rmax = ailen[0]; /* determine row with most nonzeros */ 5459 for (i = 1; i <= m; i++) { 5460 /* move each nonzero entry back by the amount of zero slots (fshift) before it*/ 5461 for (k = ai[i - 1]; k < ai[i]; k++) { 5462 if (aa[k] == 0 && (aj[k] != i - 1 || !keep)) fshift++; 5463 else { 5464 if (aa[k] == 0 && aj[k] == i - 1) PetscCall(PetscInfo(A, "Keep the diagonal zero at row %" PetscInt_FMT "\n", i - 1)); 5465 aa[k - fshift] = aa[k]; 5466 aj[k - fshift] = aj[k]; 5467 } 5468 } 5469 ai[i - 1] -= fshift_prev; // safe to update ai[i-1] now since it will not be used in the next iteration 5470 fshift_prev = fshift; 5471 /* reset ilen and imax for each row */ 5472 ailen[i - 1] = imax[i - 1] = ai[i] - fshift - ai[i - 1]; 5473 a->nonzerorowcnt += ((ai[i] - fshift - ai[i - 1]) > 0); 5474 rmax = PetscMax(rmax, ailen[i - 1]); 5475 } 5476 if (fshift) { 5477 if (m) { 5478 ai[m] -= fshift; 5479 a->nz = ai[m]; 5480 } 5481 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)); 5482 A->nonzerostate++; 5483 A->info.nz_unneeded += (PetscReal)fshift; 5484 a->rmax = rmax; 5485 if (a->inode.use && a->inode.checked) PetscCall(MatSeqAIJCheckInode(A)); 5486 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 5487 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 5488 } 5489 PetscFunctionReturn(PETSC_SUCCESS); 5490 } 5491 5492 PetscFunctionList MatSeqAIJList = NULL; 5493 5494 /*@ 5495 MatSeqAIJSetType - Converts a `MATSEQAIJ` matrix to a subtype 5496 5497 Collective 5498 5499 Input Parameters: 5500 + mat - the matrix object 5501 - matype - matrix type 5502 5503 Options Database Key: 5504 . -mat_seqaij_type <method> - for example seqaijcrl 5505 5506 Level: intermediate 5507 5508 .seealso: [](ch_matrices), `Mat`, `PCSetType()`, `VecSetType()`, `MatCreate()`, `MatType` 5509 @*/ 5510 PetscErrorCode MatSeqAIJSetType(Mat mat, MatType matype) 5511 { 5512 PetscBool sametype; 5513 PetscErrorCode (*r)(Mat, MatType, MatReuse, Mat *); 5514 5515 PetscFunctionBegin; 5516 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 5517 PetscCall(PetscObjectTypeCompare((PetscObject)mat, matype, &sametype)); 5518 if (sametype) PetscFunctionReturn(PETSC_SUCCESS); 5519 5520 PetscCall(PetscFunctionListFind(MatSeqAIJList, matype, &r)); 5521 PetscCheck(r, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown Mat type given: %s", matype); 5522 PetscCall((*r)(mat, matype, MAT_INPLACE_MATRIX, &mat)); 5523 PetscFunctionReturn(PETSC_SUCCESS); 5524 } 5525 5526 /*@C 5527 MatSeqAIJRegister - - Adds a new sub-matrix type for sequential `MATSEQAIJ` matrices 5528 5529 Not Collective, No Fortran Support 5530 5531 Input Parameters: 5532 + sname - name of a new user-defined matrix type, for example `MATSEQAIJCRL` 5533 - function - routine to convert to subtype 5534 5535 Level: advanced 5536 5537 Notes: 5538 `MatSeqAIJRegister()` may be called multiple times to add several user-defined solvers. 5539 5540 Then, your matrix can be chosen with the procedural interface at runtime via the option 5541 $ -mat_seqaij_type my_mat 5542 5543 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJRegisterAll()` 5544 @*/ 5545 PetscErrorCode MatSeqAIJRegister(const char sname[], PetscErrorCode (*function)(Mat, MatType, MatReuse, Mat *)) 5546 { 5547 PetscFunctionBegin; 5548 PetscCall(MatInitializePackage()); 5549 PetscCall(PetscFunctionListAdd(&MatSeqAIJList, sname, function)); 5550 PetscFunctionReturn(PETSC_SUCCESS); 5551 } 5552 5553 PetscBool MatSeqAIJRegisterAllCalled = PETSC_FALSE; 5554 5555 /*@C 5556 MatSeqAIJRegisterAll - Registers all of the matrix subtypes of `MATSSEQAIJ` 5557 5558 Not Collective 5559 5560 Level: advanced 5561 5562 Note: 5563 This registers the versions of `MATSEQAIJ` for GPUs 5564 5565 .seealso: [](ch_matrices), `Mat`, `MatRegisterAll()`, `MatSeqAIJRegister()` 5566 @*/ 5567 PetscErrorCode MatSeqAIJRegisterAll(void) 5568 { 5569 PetscFunctionBegin; 5570 if (MatSeqAIJRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS); 5571 MatSeqAIJRegisterAllCalled = PETSC_TRUE; 5572 5573 PetscCall(MatSeqAIJRegister(MATSEQAIJCRL, MatConvert_SeqAIJ_SeqAIJCRL)); 5574 PetscCall(MatSeqAIJRegister(MATSEQAIJPERM, MatConvert_SeqAIJ_SeqAIJPERM)); 5575 PetscCall(MatSeqAIJRegister(MATSEQAIJSELL, MatConvert_SeqAIJ_SeqAIJSELL)); 5576 #if defined(PETSC_HAVE_MKL_SPARSE) 5577 PetscCall(MatSeqAIJRegister(MATSEQAIJMKL, MatConvert_SeqAIJ_SeqAIJMKL)); 5578 #endif 5579 #if defined(PETSC_HAVE_CUDA) 5580 PetscCall(MatSeqAIJRegister(MATSEQAIJCUSPARSE, MatConvert_SeqAIJ_SeqAIJCUSPARSE)); 5581 #endif 5582 #if defined(PETSC_HAVE_HIP) 5583 PetscCall(MatSeqAIJRegister(MATSEQAIJHIPSPARSE, MatConvert_SeqAIJ_SeqAIJHIPSPARSE)); 5584 #endif 5585 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 5586 PetscCall(MatSeqAIJRegister(MATSEQAIJKOKKOS, MatConvert_SeqAIJ_SeqAIJKokkos)); 5587 #endif 5588 #if defined(PETSC_HAVE_VIENNACL) && defined(PETSC_HAVE_VIENNACL_NO_CUDA) 5589 PetscCall(MatSeqAIJRegister(MATMPIAIJVIENNACL, MatConvert_SeqAIJ_SeqAIJViennaCL)); 5590 #endif 5591 PetscFunctionReturn(PETSC_SUCCESS); 5592 } 5593 5594 /* 5595 Special version for direct calls from Fortran 5596 */ 5597 #if defined(PETSC_HAVE_FORTRAN_CAPS) 5598 #define matsetvaluesseqaij_ MATSETVALUESSEQAIJ 5599 #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE) 5600 #define matsetvaluesseqaij_ matsetvaluesseqaij 5601 #endif 5602 5603 /* Change these macros so can be used in void function */ 5604 5605 /* Change these macros so can be used in void function */ 5606 /* Identical to PetscCallVoid, except it assigns to *_ierr */ 5607 #undef PetscCall 5608 #define PetscCall(...) \ 5609 do { \ 5610 PetscErrorCode ierr_msv_mpiaij = __VA_ARGS__; \ 5611 if (PetscUnlikely(ierr_msv_mpiaij)) { \ 5612 *_ierr = PetscError(PETSC_COMM_SELF, __LINE__, PETSC_FUNCTION_NAME, __FILE__, ierr_msv_mpiaij, PETSC_ERROR_REPEAT, " "); \ 5613 return; \ 5614 } \ 5615 } while (0) 5616 5617 #undef SETERRQ 5618 #define SETERRQ(comm, ierr, ...) \ 5619 do { \ 5620 *_ierr = PetscError(comm, __LINE__, PETSC_FUNCTION_NAME, __FILE__, ierr, PETSC_ERROR_INITIAL, __VA_ARGS__); \ 5621 return; \ 5622 } while (0) 5623 5624 PETSC_EXTERN void matsetvaluesseqaij_(Mat *AA, PetscInt *mm, const PetscInt im[], PetscInt *nn, const PetscInt in[], const PetscScalar v[], InsertMode *isis, PetscErrorCode *_ierr) 5625 { 5626 Mat A = *AA; 5627 PetscInt m = *mm, n = *nn; 5628 InsertMode is = *isis; 5629 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 5630 PetscInt *rp, k, low, high, t, ii, row, nrow, i, col, l, rmax, N; 5631 PetscInt *imax, *ai, *ailen; 5632 PetscInt *aj, nonew = a->nonew, lastcol = -1; 5633 MatScalar *ap, value, *aa; 5634 PetscBool ignorezeroentries = a->ignorezeroentries; 5635 PetscBool roworiented = a->roworiented; 5636 5637 PetscFunctionBegin; 5638 MatCheckPreallocated(A, 1); 5639 imax = a->imax; 5640 ai = a->i; 5641 ailen = a->ilen; 5642 aj = a->j; 5643 aa = a->a; 5644 5645 for (k = 0; k < m; k++) { /* loop over added rows */ 5646 row = im[k]; 5647 if (row < 0) continue; 5648 PetscCheck(row < A->rmap->n, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large"); 5649 rp = aj + ai[row]; 5650 ap = aa + ai[row]; 5651 rmax = imax[row]; 5652 nrow = ailen[row]; 5653 low = 0; 5654 high = nrow; 5655 for (l = 0; l < n; l++) { /* loop over added columns */ 5656 if (in[l] < 0) continue; 5657 PetscCheck(in[l] < A->cmap->n, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Column too large"); 5658 col = in[l]; 5659 if (roworiented) value = v[l + k * n]; 5660 else value = v[k + l * m]; 5661 5662 if (value == 0.0 && ignorezeroentries && (is == ADD_VALUES)) continue; 5663 5664 if (col <= lastcol) low = 0; 5665 else high = nrow; 5666 lastcol = col; 5667 while (high - low > 5) { 5668 t = (low + high) / 2; 5669 if (rp[t] > col) high = t; 5670 else low = t; 5671 } 5672 for (i = low; i < high; i++) { 5673 if (rp[i] > col) break; 5674 if (rp[i] == col) { 5675 if (is == ADD_VALUES) ap[i] += value; 5676 else ap[i] = value; 5677 goto noinsert; 5678 } 5679 } 5680 if (value == 0.0 && ignorezeroentries) goto noinsert; 5681 if (nonew == 1) goto noinsert; 5682 PetscCheck(nonew != -1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero in the matrix"); 5683 MatSeqXAIJReallocateAIJ(A, A->rmap->n, 1, nrow, row, col, rmax, aa, ai, aj, rp, ap, imax, nonew, MatScalar); 5684 N = nrow++ - 1; 5685 a->nz++; 5686 high++; 5687 /* shift up all the later entries in this row */ 5688 for (ii = N; ii >= i; ii--) { 5689 rp[ii + 1] = rp[ii]; 5690 ap[ii + 1] = ap[ii]; 5691 } 5692 rp[i] = col; 5693 ap[i] = value; 5694 noinsert:; 5695 low = i + 1; 5696 } 5697 ailen[row] = nrow; 5698 } 5699 PetscFunctionReturnVoid(); 5700 } 5701 /* Undefining these here since they were redefined from their original definition above! No 5702 * other PETSc functions should be defined past this point, as it is impossible to recover the 5703 * original definitions */ 5704 #undef PetscCall 5705 #undef SETERRQ 5706