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