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 > 0 && 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 = PetscAbs(A->rmap->bs), mbs = A->rmap->n / bs, ipvt[5], bs2 = bs * bs, *v_pivots, ij[7], *IJ, j; 3304 MatScalar *diag, work[25], *v_work; 3305 const PetscReal shift = 0.0; 3306 PetscBool allowzeropivot, zeropivotdetected = PETSC_FALSE; 3307 3308 PetscFunctionBegin; 3309 allowzeropivot = PetscNot(A->erroriffailure); 3310 if (a->ibdiagvalid) { 3311 if (values) *values = a->ibdiag; 3312 PetscFunctionReturn(PETSC_SUCCESS); 3313 } 3314 PetscCall(MatMarkDiagonal_SeqAIJ(A)); 3315 if (!a->ibdiag) { PetscCall(PetscMalloc1(bs2 * mbs, &a->ibdiag)); } 3316 diag = a->ibdiag; 3317 if (values) *values = a->ibdiag; 3318 /* factor and invert each block */ 3319 switch (bs) { 3320 case 1: 3321 for (i = 0; i < mbs; i++) { 3322 PetscCall(MatGetValues(A, 1, &i, 1, &i, diag + i)); 3323 if (PetscAbsScalar(diag[i] + shift) < PETSC_MACHINE_EPSILON) { 3324 if (allowzeropivot) { 3325 A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3326 A->factorerror_zeropivot_value = PetscAbsScalar(diag[i]); 3327 A->factorerror_zeropivot_row = i; 3328 PetscCall(PetscInfo(A, "Zero pivot, row %" PetscInt_FMT " pivot %g tolerance %g\n", i, (double)PetscAbsScalar(diag[i]), (double)PETSC_MACHINE_EPSILON)); 3329 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_MAT_LU_ZRPVT, "Zero pivot, row %" PetscInt_FMT " pivot %g tolerance %g", i, (double)PetscAbsScalar(diag[i]), (double)PETSC_MACHINE_EPSILON); 3330 } 3331 diag[i] = (PetscScalar)1.0 / (diag[i] + shift); 3332 } 3333 break; 3334 case 2: 3335 for (i = 0; i < mbs; i++) { 3336 ij[0] = 2 * i; 3337 ij[1] = 2 * i + 1; 3338 PetscCall(MatGetValues(A, 2, ij, 2, ij, diag)); 3339 PetscCall(PetscKernel_A_gets_inverse_A_2(diag, shift, allowzeropivot, &zeropivotdetected)); 3340 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3341 PetscCall(PetscKernel_A_gets_transpose_A_2(diag)); 3342 diag += 4; 3343 } 3344 break; 3345 case 3: 3346 for (i = 0; i < mbs; i++) { 3347 ij[0] = 3 * i; 3348 ij[1] = 3 * i + 1; 3349 ij[2] = 3 * i + 2; 3350 PetscCall(MatGetValues(A, 3, ij, 3, ij, diag)); 3351 PetscCall(PetscKernel_A_gets_inverse_A_3(diag, shift, allowzeropivot, &zeropivotdetected)); 3352 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3353 PetscCall(PetscKernel_A_gets_transpose_A_3(diag)); 3354 diag += 9; 3355 } 3356 break; 3357 case 4: 3358 for (i = 0; i < mbs; i++) { 3359 ij[0] = 4 * i; 3360 ij[1] = 4 * i + 1; 3361 ij[2] = 4 * i + 2; 3362 ij[3] = 4 * i + 3; 3363 PetscCall(MatGetValues(A, 4, ij, 4, ij, diag)); 3364 PetscCall(PetscKernel_A_gets_inverse_A_4(diag, shift, allowzeropivot, &zeropivotdetected)); 3365 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3366 PetscCall(PetscKernel_A_gets_transpose_A_4(diag)); 3367 diag += 16; 3368 } 3369 break; 3370 case 5: 3371 for (i = 0; i < mbs; i++) { 3372 ij[0] = 5 * i; 3373 ij[1] = 5 * i + 1; 3374 ij[2] = 5 * i + 2; 3375 ij[3] = 5 * i + 3; 3376 ij[4] = 5 * i + 4; 3377 PetscCall(MatGetValues(A, 5, ij, 5, ij, diag)); 3378 PetscCall(PetscKernel_A_gets_inverse_A_5(diag, ipvt, work, shift, allowzeropivot, &zeropivotdetected)); 3379 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3380 PetscCall(PetscKernel_A_gets_transpose_A_5(diag)); 3381 diag += 25; 3382 } 3383 break; 3384 case 6: 3385 for (i = 0; i < mbs; i++) { 3386 ij[0] = 6 * i; 3387 ij[1] = 6 * i + 1; 3388 ij[2] = 6 * i + 2; 3389 ij[3] = 6 * i + 3; 3390 ij[4] = 6 * i + 4; 3391 ij[5] = 6 * i + 5; 3392 PetscCall(MatGetValues(A, 6, ij, 6, ij, diag)); 3393 PetscCall(PetscKernel_A_gets_inverse_A_6(diag, shift, allowzeropivot, &zeropivotdetected)); 3394 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3395 PetscCall(PetscKernel_A_gets_transpose_A_6(diag)); 3396 diag += 36; 3397 } 3398 break; 3399 case 7: 3400 for (i = 0; i < mbs; i++) { 3401 ij[0] = 7 * i; 3402 ij[1] = 7 * i + 1; 3403 ij[2] = 7 * i + 2; 3404 ij[3] = 7 * i + 3; 3405 ij[4] = 7 * i + 4; 3406 ij[5] = 7 * i + 5; 3407 ij[6] = 7 * i + 6; 3408 PetscCall(MatGetValues(A, 7, ij, 7, ij, diag)); 3409 PetscCall(PetscKernel_A_gets_inverse_A_7(diag, shift, allowzeropivot, &zeropivotdetected)); 3410 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3411 PetscCall(PetscKernel_A_gets_transpose_A_7(diag)); 3412 diag += 49; 3413 } 3414 break; 3415 default: 3416 PetscCall(PetscMalloc3(bs, &v_work, bs, &v_pivots, bs, &IJ)); 3417 for (i = 0; i < mbs; i++) { 3418 for (j = 0; j < bs; j++) IJ[j] = bs * i + j; 3419 PetscCall(MatGetValues(A, bs, IJ, bs, IJ, diag)); 3420 PetscCall(PetscKernel_A_gets_inverse_A(bs, diag, v_pivots, v_work, allowzeropivot, &zeropivotdetected)); 3421 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3422 PetscCall(PetscKernel_A_gets_transpose_A_N(diag, bs)); 3423 diag += bs2; 3424 } 3425 PetscCall(PetscFree3(v_work, v_pivots, IJ)); 3426 } 3427 a->ibdiagvalid = PETSC_TRUE; 3428 PetscFunctionReturn(PETSC_SUCCESS); 3429 } 3430 3431 static PetscErrorCode MatSetRandom_SeqAIJ(Mat x, PetscRandom rctx) 3432 { 3433 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)x->data; 3434 PetscScalar a, *aa; 3435 PetscInt m, n, i, j, col; 3436 3437 PetscFunctionBegin; 3438 if (!x->assembled) { 3439 PetscCall(MatGetSize(x, &m, &n)); 3440 for (i = 0; i < m; i++) { 3441 for (j = 0; j < aij->imax[i]; j++) { 3442 PetscCall(PetscRandomGetValue(rctx, &a)); 3443 col = (PetscInt)(n * PetscRealPart(a)); 3444 PetscCall(MatSetValues(x, 1, &i, 1, &col, &a, ADD_VALUES)); 3445 } 3446 } 3447 } else { 3448 PetscCall(MatSeqAIJGetArrayWrite(x, &aa)); 3449 for (i = 0; i < aij->nz; i++) PetscCall(PetscRandomGetValue(rctx, aa + i)); 3450 PetscCall(MatSeqAIJRestoreArrayWrite(x, &aa)); 3451 } 3452 PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY)); 3453 PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY)); 3454 PetscFunctionReturn(PETSC_SUCCESS); 3455 } 3456 3457 /* Like MatSetRandom_SeqAIJ, but do not set values on columns in range of [low, high) */ 3458 PetscErrorCode MatSetRandomSkipColumnRange_SeqAIJ_Private(Mat x, PetscInt low, PetscInt high, PetscRandom rctx) 3459 { 3460 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)x->data; 3461 PetscScalar a; 3462 PetscInt m, n, i, j, col, nskip; 3463 3464 PetscFunctionBegin; 3465 nskip = high - low; 3466 PetscCall(MatGetSize(x, &m, &n)); 3467 n -= nskip; /* shrink number of columns where nonzeros can be set */ 3468 for (i = 0; i < m; i++) { 3469 for (j = 0; j < aij->imax[i]; j++) { 3470 PetscCall(PetscRandomGetValue(rctx, &a)); 3471 col = (PetscInt)(n * PetscRealPart(a)); 3472 if (col >= low) col += nskip; /* shift col rightward to skip the hole */ 3473 PetscCall(MatSetValues(x, 1, &i, 1, &col, &a, ADD_VALUES)); 3474 } 3475 } 3476 PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY)); 3477 PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY)); 3478 PetscFunctionReturn(PETSC_SUCCESS); 3479 } 3480 3481 static struct _MatOps MatOps_Values = {MatSetValues_SeqAIJ, 3482 MatGetRow_SeqAIJ, 3483 MatRestoreRow_SeqAIJ, 3484 MatMult_SeqAIJ, 3485 /* 4*/ MatMultAdd_SeqAIJ, 3486 MatMultTranspose_SeqAIJ, 3487 MatMultTransposeAdd_SeqAIJ, 3488 NULL, 3489 NULL, 3490 NULL, 3491 /* 10*/ NULL, 3492 MatLUFactor_SeqAIJ, 3493 NULL, 3494 MatSOR_SeqAIJ, 3495 MatTranspose_SeqAIJ, 3496 /*1 5*/ MatGetInfo_SeqAIJ, 3497 MatEqual_SeqAIJ, 3498 MatGetDiagonal_SeqAIJ, 3499 MatDiagonalScale_SeqAIJ, 3500 MatNorm_SeqAIJ, 3501 /* 20*/ NULL, 3502 MatAssemblyEnd_SeqAIJ, 3503 MatSetOption_SeqAIJ, 3504 MatZeroEntries_SeqAIJ, 3505 /* 24*/ MatZeroRows_SeqAIJ, 3506 NULL, 3507 NULL, 3508 NULL, 3509 NULL, 3510 /* 29*/ MatSetUp_Seq_Hash, 3511 NULL, 3512 NULL, 3513 NULL, 3514 NULL, 3515 /* 34*/ MatDuplicate_SeqAIJ, 3516 NULL, 3517 NULL, 3518 MatILUFactor_SeqAIJ, 3519 NULL, 3520 /* 39*/ MatAXPY_SeqAIJ, 3521 MatCreateSubMatrices_SeqAIJ, 3522 MatIncreaseOverlap_SeqAIJ, 3523 MatGetValues_SeqAIJ, 3524 MatCopy_SeqAIJ, 3525 /* 44*/ MatGetRowMax_SeqAIJ, 3526 MatScale_SeqAIJ, 3527 MatShift_SeqAIJ, 3528 MatDiagonalSet_SeqAIJ, 3529 MatZeroRowsColumns_SeqAIJ, 3530 /* 49*/ MatSetRandom_SeqAIJ, 3531 MatGetRowIJ_SeqAIJ, 3532 MatRestoreRowIJ_SeqAIJ, 3533 MatGetColumnIJ_SeqAIJ, 3534 MatRestoreColumnIJ_SeqAIJ, 3535 /* 54*/ MatFDColoringCreate_SeqXAIJ, 3536 NULL, 3537 NULL, 3538 MatPermute_SeqAIJ, 3539 NULL, 3540 /* 59*/ NULL, 3541 MatDestroy_SeqAIJ, 3542 MatView_SeqAIJ, 3543 NULL, 3544 NULL, 3545 /* 64*/ NULL, 3546 MatMatMatMultNumeric_SeqAIJ_SeqAIJ_SeqAIJ, 3547 NULL, 3548 NULL, 3549 NULL, 3550 /* 69*/ MatGetRowMaxAbs_SeqAIJ, 3551 MatGetRowMinAbs_SeqAIJ, 3552 NULL, 3553 NULL, 3554 NULL, 3555 /* 74*/ NULL, 3556 MatFDColoringApply_AIJ, 3557 NULL, 3558 NULL, 3559 NULL, 3560 /* 79*/ MatFindZeroDiagonals_SeqAIJ, 3561 NULL, 3562 NULL, 3563 NULL, 3564 MatLoad_SeqAIJ, 3565 /* 84*/ NULL, 3566 NULL, 3567 NULL, 3568 NULL, 3569 NULL, 3570 /* 89*/ NULL, 3571 NULL, 3572 MatMatMultNumeric_SeqAIJ_SeqAIJ, 3573 NULL, 3574 NULL, 3575 /* 94*/ MatPtAPNumeric_SeqAIJ_SeqAIJ_SparseAxpy, 3576 NULL, 3577 NULL, 3578 MatMatTransposeMultNumeric_SeqAIJ_SeqAIJ, 3579 NULL, 3580 /* 99*/ MatProductSetFromOptions_SeqAIJ, 3581 NULL, 3582 NULL, 3583 MatConjugate_SeqAIJ, 3584 NULL, 3585 /*104*/ MatSetValuesRow_SeqAIJ, 3586 MatRealPart_SeqAIJ, 3587 MatImaginaryPart_SeqAIJ, 3588 NULL, 3589 NULL, 3590 /*109*/ MatMatSolve_SeqAIJ, 3591 NULL, 3592 MatGetRowMin_SeqAIJ, 3593 NULL, 3594 MatMissingDiagonal_SeqAIJ, 3595 /*114*/ NULL, 3596 NULL, 3597 NULL, 3598 NULL, 3599 NULL, 3600 /*119*/ NULL, 3601 NULL, 3602 NULL, 3603 NULL, 3604 MatGetMultiProcBlock_SeqAIJ, 3605 /*124*/ MatFindNonzeroRows_SeqAIJ, 3606 MatGetColumnReductions_SeqAIJ, 3607 MatInvertBlockDiagonal_SeqAIJ, 3608 MatInvertVariableBlockDiagonal_SeqAIJ, 3609 NULL, 3610 /*129*/ NULL, 3611 NULL, 3612 NULL, 3613 MatTransposeMatMultNumeric_SeqAIJ_SeqAIJ, 3614 MatTransposeColoringCreate_SeqAIJ, 3615 /*134*/ MatTransColoringApplySpToDen_SeqAIJ, 3616 MatTransColoringApplyDenToSp_SeqAIJ, 3617 NULL, 3618 NULL, 3619 MatRARtNumeric_SeqAIJ_SeqAIJ, 3620 /*139*/ NULL, 3621 NULL, 3622 NULL, 3623 MatFDColoringSetUp_SeqXAIJ, 3624 MatFindOffBlockDiagonalEntries_SeqAIJ, 3625 MatCreateMPIMatConcatenateSeqMat_SeqAIJ, 3626 /*145*/ MatDestroySubMatrices_SeqAIJ, 3627 NULL, 3628 NULL, 3629 MatCreateGraph_Simple_AIJ, 3630 NULL, 3631 /*150*/ MatTransposeSymbolic_SeqAIJ, 3632 MatEliminateZeros_SeqAIJ, 3633 MatGetRowSumAbs_SeqAIJ, 3634 NULL, 3635 NULL, 3636 /*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 static PetscErrorCode MatResetPreallocation_SeqAIJ(Mat A) 4056 { 4057 Mat_SeqAIJ *a; 4058 PetscInt i; 4059 PetscBool skipreset; 4060 4061 PetscFunctionBegin; 4062 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 4063 4064 /* Check local size. If zero, then return */ 4065 if (!A->rmap->n) PetscFunctionReturn(PETSC_SUCCESS); 4066 4067 a = (Mat_SeqAIJ *)A->data; 4068 /* if no saved info, we error out */ 4069 PetscCheck(a->ipre, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "No saved preallocation info "); 4070 4071 PetscCheck(a->i && a->imax && a->ilen, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Memory info is incomplete, and can not reset preallocation "); 4072 4073 PetscCall(PetscArraycmp(a->ipre, a->ilen, A->rmap->n, &skipreset)); 4074 if (!skipreset) { 4075 PetscCall(PetscArraycpy(a->imax, a->ipre, A->rmap->n)); 4076 PetscCall(PetscArrayzero(a->ilen, A->rmap->n)); 4077 a->i[0] = 0; 4078 for (i = 1; i < A->rmap->n + 1; i++) a->i[i] = a->i[i - 1] + a->imax[i - 1]; 4079 A->preallocated = PETSC_TRUE; 4080 a->nz = 0; 4081 a->maxnz = a->i[A->rmap->n]; 4082 A->info.nz_unneeded = (double)a->maxnz; 4083 A->was_assembled = PETSC_FALSE; 4084 A->assembled = PETSC_FALSE; 4085 A->nonzerostate++; 4086 /* Log that the state of this object has changed; this will help guarantee that preconditioners get re-setup */ 4087 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 4088 } 4089 PetscFunctionReturn(PETSC_SUCCESS); 4090 } 4091 4092 /*@ 4093 MatSeqAIJSetPreallocationCSR - Allocates memory for a sparse sequential matrix in `MATSEQAIJ` format. 4094 4095 Input Parameters: 4096 + B - the matrix 4097 . i - the indices into `j` for the start of each row (indices start with zero) 4098 . j - the column indices for each row (indices start with zero) these must be sorted for each row 4099 - v - optional values in the matrix, use `NULL` if not provided 4100 4101 Level: developer 4102 4103 Notes: 4104 The `i`,`j`,`v` values are COPIED with this routine; to avoid the copy use `MatCreateSeqAIJWithArrays()` 4105 4106 This routine may be called multiple times with different nonzero patterns (or the same nonzero pattern). The nonzero 4107 structure will be the union of all the previous nonzero structures. 4108 4109 Developer Notes: 4110 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 4111 then just copies the `v` values directly with `PetscMemcpy()`. 4112 4113 This routine could also take a `PetscCopyMode` argument to allow sharing the values instead of always copying them. 4114 4115 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateSeqAIJ()`, `MatSetValues()`, `MatSeqAIJSetPreallocation()`, `MATSEQAIJ`, `MatResetPreallocation()` 4116 @*/ 4117 PetscErrorCode MatSeqAIJSetPreallocationCSR(Mat B, const PetscInt i[], const PetscInt j[], const PetscScalar v[]) 4118 { 4119 PetscFunctionBegin; 4120 PetscValidHeaderSpecific(B, MAT_CLASSID, 1); 4121 PetscValidType(B, 1); 4122 PetscTryMethod(B, "MatSeqAIJSetPreallocationCSR_C", (Mat, const PetscInt[], const PetscInt[], const PetscScalar[]), (B, i, j, v)); 4123 PetscFunctionReturn(PETSC_SUCCESS); 4124 } 4125 4126 static PetscErrorCode MatSeqAIJSetPreallocationCSR_SeqAIJ(Mat B, const PetscInt Ii[], const PetscInt J[], const PetscScalar v[]) 4127 { 4128 PetscInt i; 4129 PetscInt m, n; 4130 PetscInt nz; 4131 PetscInt *nnz; 4132 4133 PetscFunctionBegin; 4134 PetscCheck(Ii[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Ii[0] must be 0 it is %" PetscInt_FMT, Ii[0]); 4135 4136 PetscCall(PetscLayoutSetUp(B->rmap)); 4137 PetscCall(PetscLayoutSetUp(B->cmap)); 4138 4139 PetscCall(MatGetSize(B, &m, &n)); 4140 PetscCall(PetscMalloc1(m + 1, &nnz)); 4141 for (i = 0; i < m; i++) { 4142 nz = Ii[i + 1] - Ii[i]; 4143 PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local row %" PetscInt_FMT " has a negative number of columns %" PetscInt_FMT, i, nz); 4144 nnz[i] = nz; 4145 } 4146 PetscCall(MatSeqAIJSetPreallocation(B, 0, nnz)); 4147 PetscCall(PetscFree(nnz)); 4148 4149 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)); 4150 4151 PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY)); 4152 PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY)); 4153 4154 PetscCall(MatSetOption(B, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE)); 4155 PetscFunctionReturn(PETSC_SUCCESS); 4156 } 4157 4158 /*@ 4159 MatSeqAIJKron - Computes `C`, the Kronecker product of `A` and `B`. 4160 4161 Input Parameters: 4162 + A - left-hand side matrix 4163 . B - right-hand side matrix 4164 - reuse - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX` 4165 4166 Output Parameter: 4167 . C - Kronecker product of `A` and `B` 4168 4169 Level: intermediate 4170 4171 Note: 4172 `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the product matrix has not changed from that last call to `MatSeqAIJKron()`. 4173 4174 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MATKAIJ`, `MatReuse` 4175 @*/ 4176 PetscErrorCode MatSeqAIJKron(Mat A, Mat B, MatReuse reuse, Mat *C) 4177 { 4178 PetscFunctionBegin; 4179 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 4180 PetscValidType(A, 1); 4181 PetscValidHeaderSpecific(B, MAT_CLASSID, 2); 4182 PetscValidType(B, 2); 4183 PetscAssertPointer(C, 4); 4184 if (reuse == MAT_REUSE_MATRIX) { 4185 PetscValidHeaderSpecific(*C, MAT_CLASSID, 4); 4186 PetscValidType(*C, 4); 4187 } 4188 PetscTryMethod(A, "MatSeqAIJKron_C", (Mat, Mat, MatReuse, Mat *), (A, B, reuse, C)); 4189 PetscFunctionReturn(PETSC_SUCCESS); 4190 } 4191 4192 static PetscErrorCode MatSeqAIJKron_SeqAIJ(Mat A, Mat B, MatReuse reuse, Mat *C) 4193 { 4194 Mat newmat; 4195 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 4196 Mat_SeqAIJ *b = (Mat_SeqAIJ *)B->data; 4197 PetscScalar *v; 4198 const PetscScalar *aa, *ba; 4199 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; 4200 PetscBool flg; 4201 4202 PetscFunctionBegin; 4203 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 4204 PetscCheck(A->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 4205 PetscCheck(!B->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 4206 PetscCheck(B->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 4207 PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &flg)); 4208 PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatType %s", ((PetscObject)B)->type_name); 4209 PetscCheck(reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatReuse %d", (int)reuse); 4210 if (reuse == MAT_INITIAL_MATRIX) { 4211 PetscCall(PetscMalloc2(am * bm + 1, &i, a->i[am] * b->i[bm], &j)); 4212 PetscCall(MatCreate(PETSC_COMM_SELF, &newmat)); 4213 PetscCall(MatSetSizes(newmat, am * bm, an * bn, am * bm, an * bn)); 4214 PetscCall(MatSetType(newmat, MATAIJ)); 4215 i[0] = 0; 4216 for (m = 0; m < am; ++m) { 4217 for (p = 0; p < bm; ++p) { 4218 i[m * bm + p + 1] = i[m * bm + p] + (a->i[m + 1] - a->i[m]) * (b->i[p + 1] - b->i[p]); 4219 for (n = a->i[m]; n < a->i[m + 1]; ++n) { 4220 for (q = b->i[p]; q < b->i[p + 1]; ++q) j[nnz++] = a->j[n] * bn + b->j[q]; 4221 } 4222 } 4223 } 4224 PetscCall(MatSeqAIJSetPreallocationCSR(newmat, i, j, NULL)); 4225 *C = newmat; 4226 PetscCall(PetscFree2(i, j)); 4227 nnz = 0; 4228 } 4229 PetscCall(MatSeqAIJGetArray(*C, &v)); 4230 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 4231 PetscCall(MatSeqAIJGetArrayRead(B, &ba)); 4232 for (m = 0; m < am; ++m) { 4233 for (p = 0; p < bm; ++p) { 4234 for (n = a->i[m]; n < a->i[m + 1]; ++n) { 4235 for (q = b->i[p]; q < b->i[p + 1]; ++q) v[nnz++] = aa[n] * ba[q]; 4236 } 4237 } 4238 } 4239 PetscCall(MatSeqAIJRestoreArray(*C, &v)); 4240 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 4241 PetscCall(MatSeqAIJRestoreArrayRead(B, &ba)); 4242 PetscFunctionReturn(PETSC_SUCCESS); 4243 } 4244 4245 #include <../src/mat/impls/dense/seq/dense.h> 4246 #include <petsc/private/kernels/petscaxpy.h> 4247 4248 /* 4249 Computes (B'*A')' since computing B*A directly is untenable 4250 4251 n p p 4252 [ ] [ ] [ ] 4253 m [ A ] * n [ B ] = m [ C ] 4254 [ ] [ ] [ ] 4255 4256 */ 4257 PetscErrorCode MatMatMultNumeric_SeqDense_SeqAIJ(Mat A, Mat B, Mat C) 4258 { 4259 Mat_SeqDense *sub_a = (Mat_SeqDense *)A->data; 4260 Mat_SeqAIJ *sub_b = (Mat_SeqAIJ *)B->data; 4261 Mat_SeqDense *sub_c = (Mat_SeqDense *)C->data; 4262 PetscInt i, j, n, m, q, p; 4263 const PetscInt *ii, *idx; 4264 const PetscScalar *b, *a, *a_q; 4265 PetscScalar *c, *c_q; 4266 PetscInt clda = sub_c->lda; 4267 PetscInt alda = sub_a->lda; 4268 4269 PetscFunctionBegin; 4270 m = A->rmap->n; 4271 n = A->cmap->n; 4272 p = B->cmap->n; 4273 a = sub_a->v; 4274 b = sub_b->a; 4275 c = sub_c->v; 4276 if (clda == m) { 4277 PetscCall(PetscArrayzero(c, m * p)); 4278 } else { 4279 for (j = 0; j < p; j++) 4280 for (i = 0; i < m; i++) c[j * clda + i] = 0.0; 4281 } 4282 ii = sub_b->i; 4283 idx = sub_b->j; 4284 for (i = 0; i < n; i++) { 4285 q = ii[i + 1] - ii[i]; 4286 while (q-- > 0) { 4287 c_q = c + clda * (*idx); 4288 a_q = a + alda * i; 4289 PetscKernelAXPY(c_q, *b, a_q, m); 4290 idx++; 4291 b++; 4292 } 4293 } 4294 PetscFunctionReturn(PETSC_SUCCESS); 4295 } 4296 4297 PetscErrorCode MatMatMultSymbolic_SeqDense_SeqAIJ(Mat A, Mat B, PetscReal fill, Mat C) 4298 { 4299 PetscInt m = A->rmap->n, n = B->cmap->n; 4300 PetscBool cisdense; 4301 4302 PetscFunctionBegin; 4303 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); 4304 PetscCall(MatSetSizes(C, m, n, m, n)); 4305 PetscCall(MatSetBlockSizesFromMats(C, A, B)); 4306 PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATSEQDENSECUDA, MATSEQDENSEHIP, "")); 4307 if (!cisdense) PetscCall(MatSetType(C, MATDENSE)); 4308 PetscCall(MatSetUp(C)); 4309 4310 C->ops->matmultnumeric = MatMatMultNumeric_SeqDense_SeqAIJ; 4311 PetscFunctionReturn(PETSC_SUCCESS); 4312 } 4313 4314 /*MC 4315 MATSEQAIJ - MATSEQAIJ = "seqaij" - A matrix type to be used for sequential sparse matrices, 4316 based on compressed sparse row format. 4317 4318 Options Database Key: 4319 . -mat_type seqaij - sets the matrix type to "seqaij" during a call to MatSetFromOptions() 4320 4321 Level: beginner 4322 4323 Notes: 4324 `MatSetValues()` may be called for this matrix type with a `NULL` argument for the numerical values, 4325 in this case the values associated with the rows and columns one passes in are set to zero 4326 in the matrix 4327 4328 `MatSetOptions`(,`MAT_STRUCTURE_ONLY`,`PETSC_TRUE`) may be called for this matrix type. In this no 4329 space is allocated for the nonzero entries and any entries passed with `MatSetValues()` are ignored 4330 4331 Developer Note: 4332 It would be nice if all matrix formats supported passing `NULL` in for the numerical values 4333 4334 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MatSetFromOptions()`, `MatSetType()`, `MatCreate()`, `MatType`, `MATSELL`, `MATSEQSELL`, `MATMPISELL` 4335 M*/ 4336 4337 /*MC 4338 MATAIJ - MATAIJ = "aij" - A matrix type to be used for sparse matrices. 4339 4340 This matrix type is identical to `MATSEQAIJ` when constructed with a single process communicator, 4341 and `MATMPIAIJ` otherwise. As a result, for single process communicators, 4342 `MatSeqAIJSetPreallocation()` is supported, and similarly `MatMPIAIJSetPreallocation()` is supported 4343 for communicators controlling multiple processes. It is recommended that you call both of 4344 the above preallocation routines for simplicity. 4345 4346 Options Database Key: 4347 . -mat_type aij - sets the matrix type to "aij" during a call to `MatSetFromOptions()` 4348 4349 Level: beginner 4350 4351 Note: 4352 Subclasses include `MATAIJCUSPARSE`, `MATAIJPERM`, `MATAIJSELL`, `MATAIJMKL`, `MATAIJCRL`, and also automatically switches over to use inodes when 4353 enough exist. 4354 4355 .seealso: [](ch_matrices), `Mat`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MATMPIAIJ`, `MATSELL`, `MATSEQSELL`, `MATMPISELL` 4356 M*/ 4357 4358 /*MC 4359 MATAIJCRL - MATAIJCRL = "aijcrl" - A matrix type to be used for sparse matrices. 4360 4361 Options Database Key: 4362 . -mat_type aijcrl - sets the matrix type to "aijcrl" during a call to `MatSetFromOptions()` 4363 4364 Level: beginner 4365 4366 Note: 4367 This matrix type is identical to `MATSEQAIJCRL` when constructed with a single process communicator, 4368 and `MATMPIAIJCRL` otherwise. As a result, for single process communicators, 4369 `MatSeqAIJSetPreallocation()` is supported, and similarly `MatMPIAIJSetPreallocation()` is supported 4370 for communicators controlling multiple processes. It is recommended that you call both of 4371 the above preallocation routines for simplicity. 4372 4373 .seealso: [](ch_matrices), `Mat`, `MatCreateMPIAIJCRL`, `MATSEQAIJCRL`, `MATMPIAIJCRL`, `MATSEQAIJCRL`, `MATMPIAIJCRL` 4374 M*/ 4375 4376 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJCRL(Mat, MatType, MatReuse, Mat *); 4377 #if defined(PETSC_HAVE_ELEMENTAL) 4378 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_Elemental(Mat, MatType, MatReuse, Mat *); 4379 #endif 4380 #if defined(PETSC_HAVE_SCALAPACK) 4381 PETSC_INTERN PetscErrorCode MatConvert_AIJ_ScaLAPACK(Mat, MatType, MatReuse, Mat *); 4382 #endif 4383 #if defined(PETSC_HAVE_HYPRE) 4384 PETSC_INTERN PetscErrorCode MatConvert_AIJ_HYPRE(Mat A, MatType, MatReuse, Mat *); 4385 #endif 4386 4387 PETSC_EXTERN PetscErrorCode MatConvert_SeqAIJ_SeqSELL(Mat, MatType, MatReuse, Mat *); 4388 PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat, MatType, MatReuse, Mat *); 4389 PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat); 4390 4391 /*@C 4392 MatSeqAIJGetArray - gives read/write access to the array where the data for a `MATSEQAIJ` matrix is stored 4393 4394 Not Collective 4395 4396 Input Parameter: 4397 . A - a `MATSEQAIJ` matrix 4398 4399 Output Parameter: 4400 . array - pointer to the data 4401 4402 Level: intermediate 4403 4404 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJRestoreArray()` 4405 @*/ 4406 PetscErrorCode MatSeqAIJGetArray(Mat A, PetscScalar *array[]) 4407 { 4408 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4409 4410 PetscFunctionBegin; 4411 if (aij->ops->getarray) { 4412 PetscCall((*aij->ops->getarray)(A, array)); 4413 } else { 4414 *array = aij->a; 4415 } 4416 PetscFunctionReturn(PETSC_SUCCESS); 4417 } 4418 4419 /*@C 4420 MatSeqAIJRestoreArray - returns access to the array where the data for a `MATSEQAIJ` matrix is stored obtained by `MatSeqAIJGetArray()` 4421 4422 Not Collective 4423 4424 Input Parameters: 4425 + A - a `MATSEQAIJ` matrix 4426 - array - pointer to the data 4427 4428 Level: intermediate 4429 4430 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()` 4431 @*/ 4432 PetscErrorCode MatSeqAIJRestoreArray(Mat A, PetscScalar *array[]) 4433 { 4434 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4435 4436 PetscFunctionBegin; 4437 if (aij->ops->restorearray) { 4438 PetscCall((*aij->ops->restorearray)(A, array)); 4439 } else { 4440 *array = NULL; 4441 } 4442 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 4443 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 4444 PetscFunctionReturn(PETSC_SUCCESS); 4445 } 4446 4447 /*@C 4448 MatSeqAIJGetArrayRead - gives read-only access to the array where the data for a `MATSEQAIJ` matrix is stored 4449 4450 Not Collective; No Fortran Support 4451 4452 Input Parameter: 4453 . A - a `MATSEQAIJ` matrix 4454 4455 Output Parameter: 4456 . array - pointer to the data 4457 4458 Level: intermediate 4459 4460 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayRead()` 4461 @*/ 4462 PetscErrorCode MatSeqAIJGetArrayRead(Mat A, const PetscScalar *array[]) 4463 { 4464 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4465 4466 PetscFunctionBegin; 4467 if (aij->ops->getarrayread) { 4468 PetscCall((*aij->ops->getarrayread)(A, array)); 4469 } else { 4470 *array = aij->a; 4471 } 4472 PetscFunctionReturn(PETSC_SUCCESS); 4473 } 4474 4475 /*@C 4476 MatSeqAIJRestoreArrayRead - restore the read-only access array obtained from `MatSeqAIJGetArrayRead()` 4477 4478 Not Collective; No Fortran Support 4479 4480 Input Parameter: 4481 . A - a `MATSEQAIJ` matrix 4482 4483 Output Parameter: 4484 . array - pointer to the data 4485 4486 Level: intermediate 4487 4488 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4489 @*/ 4490 PetscErrorCode MatSeqAIJRestoreArrayRead(Mat A, const PetscScalar *array[]) 4491 { 4492 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4493 4494 PetscFunctionBegin; 4495 if (aij->ops->restorearrayread) { 4496 PetscCall((*aij->ops->restorearrayread)(A, array)); 4497 } else { 4498 *array = NULL; 4499 } 4500 PetscFunctionReturn(PETSC_SUCCESS); 4501 } 4502 4503 /*@C 4504 MatSeqAIJGetArrayWrite - gives write-only access to the array where the data for a `MATSEQAIJ` matrix is stored 4505 4506 Not Collective; No Fortran Support 4507 4508 Input Parameter: 4509 . A - a `MATSEQAIJ` matrix 4510 4511 Output Parameter: 4512 . array - pointer to the data 4513 4514 Level: intermediate 4515 4516 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayRead()` 4517 @*/ 4518 PetscErrorCode MatSeqAIJGetArrayWrite(Mat A, PetscScalar *array[]) 4519 { 4520 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4521 4522 PetscFunctionBegin; 4523 if (aij->ops->getarraywrite) { 4524 PetscCall((*aij->ops->getarraywrite)(A, array)); 4525 } else { 4526 *array = aij->a; 4527 } 4528 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 4529 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 4530 PetscFunctionReturn(PETSC_SUCCESS); 4531 } 4532 4533 /*@C 4534 MatSeqAIJRestoreArrayWrite - restore the read-only access array obtained from MatSeqAIJGetArrayRead 4535 4536 Not Collective; No Fortran Support 4537 4538 Input Parameter: 4539 . A - a MATSEQAIJ matrix 4540 4541 Output Parameter: 4542 . array - pointer to the data 4543 4544 Level: intermediate 4545 4546 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4547 @*/ 4548 PetscErrorCode MatSeqAIJRestoreArrayWrite(Mat A, PetscScalar *array[]) 4549 { 4550 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4551 4552 PetscFunctionBegin; 4553 if (aij->ops->restorearraywrite) { 4554 PetscCall((*aij->ops->restorearraywrite)(A, array)); 4555 } else { 4556 *array = NULL; 4557 } 4558 PetscFunctionReturn(PETSC_SUCCESS); 4559 } 4560 4561 /*@C 4562 MatSeqAIJGetCSRAndMemType - Get the CSR arrays and the memory type of the `MATSEQAIJ` matrix 4563 4564 Not Collective; No Fortran Support 4565 4566 Input Parameter: 4567 . mat - a matrix of type `MATSEQAIJ` or its subclasses 4568 4569 Output Parameters: 4570 + i - row map array of the matrix 4571 . j - column index array of the matrix 4572 . a - data array of the matrix 4573 - mtype - memory type of the arrays 4574 4575 Level: developer 4576 4577 Notes: 4578 Any of the output parameters can be `NULL`, in which case the corresponding value is not returned. 4579 If mat is a device matrix, the arrays are on the device. Otherwise, they are on the host. 4580 4581 One can call this routine on a preallocated but not assembled matrix to just get the memory of the CSR underneath the matrix. 4582 If the matrix is assembled, the data array `a` is guaranteed to have the latest values of the matrix. 4583 4584 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4585 @*/ 4586 PetscErrorCode MatSeqAIJGetCSRAndMemType(Mat mat, const PetscInt *i[], const PetscInt *j[], PetscScalar *a[], PetscMemType *mtype) 4587 { 4588 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 4589 4590 PetscFunctionBegin; 4591 PetscCheck(mat->preallocated, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "matrix is not preallocated"); 4592 if (aij->ops->getcsrandmemtype) { 4593 PetscCall((*aij->ops->getcsrandmemtype)(mat, i, j, a, mtype)); 4594 } else { 4595 if (i) *i = aij->i; 4596 if (j) *j = aij->j; 4597 if (a) *a = aij->a; 4598 if (mtype) *mtype = PETSC_MEMTYPE_HOST; 4599 } 4600 PetscFunctionReturn(PETSC_SUCCESS); 4601 } 4602 4603 /*@ 4604 MatSeqAIJGetMaxRowNonzeros - returns the maximum number of nonzeros in any row 4605 4606 Not Collective 4607 4608 Input Parameter: 4609 . A - a `MATSEQAIJ` matrix 4610 4611 Output Parameter: 4612 . nz - the maximum number of nonzeros in any row 4613 4614 Level: intermediate 4615 4616 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJRestoreArray()` 4617 @*/ 4618 PetscErrorCode MatSeqAIJGetMaxRowNonzeros(Mat A, PetscInt *nz) 4619 { 4620 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4621 4622 PetscFunctionBegin; 4623 *nz = aij->rmax; 4624 PetscFunctionReturn(PETSC_SUCCESS); 4625 } 4626 4627 static PetscErrorCode MatCOOStructDestroy_SeqAIJ(void **data) 4628 { 4629 MatCOOStruct_SeqAIJ *coo = (MatCOOStruct_SeqAIJ *)*data; 4630 4631 PetscFunctionBegin; 4632 PetscCall(PetscFree(coo->perm)); 4633 PetscCall(PetscFree(coo->jmap)); 4634 PetscCall(PetscFree(coo)); 4635 PetscFunctionReturn(PETSC_SUCCESS); 4636 } 4637 4638 PetscErrorCode MatSetPreallocationCOO_SeqAIJ(Mat mat, PetscCount coo_n, PetscInt coo_i[], PetscInt coo_j[]) 4639 { 4640 MPI_Comm comm; 4641 PetscInt *i, *j; 4642 PetscInt M, N, row, iprev; 4643 PetscCount k, p, q, nneg, nnz, start, end; /* Index the coo array, so use PetscCount as their type */ 4644 PetscInt *Ai; /* Change to PetscCount once we use it for row pointers */ 4645 PetscInt *Aj; 4646 PetscScalar *Aa; 4647 Mat_SeqAIJ *seqaij = (Mat_SeqAIJ *)mat->data; 4648 MatType rtype; 4649 PetscCount *perm, *jmap; 4650 MatCOOStruct_SeqAIJ *coo; 4651 PetscBool isorted; 4652 PetscBool hypre; 4653 const char *name; 4654 4655 PetscFunctionBegin; 4656 PetscCall(PetscObjectGetComm((PetscObject)mat, &comm)); 4657 PetscCall(MatGetSize(mat, &M, &N)); 4658 i = coo_i; 4659 j = coo_j; 4660 PetscCall(PetscMalloc1(coo_n, &perm)); 4661 4662 /* 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) */ 4663 isorted = PETSC_TRUE; 4664 iprev = PETSC_INT_MIN; 4665 for (k = 0; k < coo_n; k++) { 4666 if (j[k] < 0) i[k] = -1; 4667 if (isorted) { 4668 if (i[k] < iprev) isorted = PETSC_FALSE; 4669 else iprev = i[k]; 4670 } 4671 perm[k] = k; 4672 } 4673 4674 /* Sort by row if not already */ 4675 if (!isorted) PetscCall(PetscSortIntWithIntCountArrayPair(coo_n, i, j, perm)); 4676 4677 /* Advance k to the first row with a non-negative index */ 4678 for (k = 0; k < coo_n; k++) 4679 if (i[k] >= 0) break; 4680 nneg = k; 4681 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 */ 4682 nnz = 0; /* Total number of unique nonzeros to be counted */ 4683 jmap++; /* Inc jmap by 1 for convenience */ 4684 4685 PetscCall(PetscShmgetAllocateArray(M + 1, sizeof(PetscInt), (void **)&Ai)); /* CSR of A */ 4686 PetscCall(PetscArrayzero(Ai, M + 1)); 4687 PetscCall(PetscShmgetAllocateArray(coo_n - nneg, sizeof(PetscInt), (void **)&Aj)); /* We have at most coo_n-nneg unique nonzeros */ 4688 4689 PetscCall(PetscObjectGetName((PetscObject)mat, &name)); 4690 PetscCall(PetscStrcmp("_internal_COO_mat_for_hypre", name, &hypre)); 4691 4692 /* In each row, sort by column, then unique column indices to get row length */ 4693 Ai++; /* Inc by 1 for convenience */ 4694 q = 0; /* q-th unique nonzero, with q starting from 0 */ 4695 while (k < coo_n) { 4696 PetscBool strictly_sorted; // this row is strictly sorted? 4697 PetscInt jprev; 4698 4699 /* get [start,end) indices for this row; also check if cols in this row are strictly sorted */ 4700 row = i[k]; 4701 start = k; 4702 jprev = PETSC_INT_MIN; 4703 strictly_sorted = PETSC_TRUE; 4704 while (k < coo_n && i[k] == row) { 4705 if (strictly_sorted) { 4706 if (j[k] <= jprev) strictly_sorted = PETSC_FALSE; 4707 else jprev = j[k]; 4708 } 4709 k++; 4710 } 4711 end = k; 4712 4713 /* hack for HYPRE: swap min column to diag so that diagonal values will go first */ 4714 if (hypre) { 4715 PetscInt minj = PETSC_INT_MAX; 4716 PetscBool hasdiag = PETSC_FALSE; 4717 4718 if (strictly_sorted) { // fast path to swap the first and the diag 4719 PetscCount tmp; 4720 for (p = start; p < end; p++) { 4721 if (j[p] == row && p != start) { 4722 j[p] = j[start]; // swap j[], so that the diagonal value will go first (manipulated by perm[]) 4723 j[start] = row; 4724 tmp = perm[start]; 4725 perm[start] = perm[p]; // also swap perm[] so we can save the call to PetscSortIntWithCountArray() below 4726 perm[p] = tmp; 4727 break; 4728 } 4729 } 4730 } else { 4731 for (p = start; p < end; p++) { 4732 hasdiag = (PetscBool)(hasdiag || (j[p] == row)); 4733 minj = PetscMin(minj, j[p]); 4734 } 4735 4736 if (hasdiag) { 4737 for (p = start; p < end; p++) { 4738 if (j[p] == minj) j[p] = row; 4739 else if (j[p] == row) j[p] = minj; 4740 } 4741 } 4742 } 4743 } 4744 // sort by columns in a row. perm[] indicates their original order 4745 if (!strictly_sorted) PetscCall(PetscSortIntWithCountArray(end - start, j + start, perm + start)); 4746 4747 if (strictly_sorted) { // fast path to set Aj[], jmap[], Ai[], nnz, q 4748 for (p = start; p < end; p++, q++) { 4749 Aj[q] = j[p]; 4750 jmap[q] = 1; 4751 } 4752 PetscCall(PetscIntCast(end - start, Ai + row)); 4753 nnz += Ai[row]; // q is already advanced 4754 } else { 4755 /* Find number of unique col entries in this row */ 4756 Aj[q] = j[start]; /* Log the first nonzero in this row */ 4757 jmap[q] = 1; /* Number of repeats of this nonzero entry */ 4758 Ai[row] = 1; 4759 nnz++; 4760 4761 for (p = start + 1; p < end; p++) { /* Scan remaining nonzero in this row */ 4762 if (j[p] != j[p - 1]) { /* Meet a new nonzero */ 4763 q++; 4764 jmap[q] = 1; 4765 Aj[q] = j[p]; 4766 Ai[row]++; 4767 nnz++; 4768 } else { 4769 jmap[q]++; 4770 } 4771 } 4772 q++; /* Move to next row and thus next unique nonzero */ 4773 } 4774 } 4775 4776 Ai--; /* Back to the beginning of Ai[] */ 4777 for (k = 0; k < M; k++) Ai[k + 1] += Ai[k]; 4778 jmap--; // Back to the beginning of jmap[] 4779 jmap[0] = 0; 4780 for (k = 0; k < nnz; k++) jmap[k + 1] += jmap[k]; 4781 4782 if (nnz < coo_n - nneg) { /* Reallocate with actual number of unique nonzeros */ 4783 PetscCount *jmap_new; 4784 PetscInt *Aj_new; 4785 4786 PetscCall(PetscMalloc1(nnz + 1, &jmap_new)); 4787 PetscCall(PetscArraycpy(jmap_new, jmap, nnz + 1)); 4788 PetscCall(PetscFree(jmap)); 4789 jmap = jmap_new; 4790 4791 PetscCall(PetscShmgetAllocateArray(nnz, sizeof(PetscInt), (void **)&Aj_new)); 4792 PetscCall(PetscArraycpy(Aj_new, Aj, nnz)); 4793 PetscCall(PetscShmgetDeallocateArray((void **)&Aj)); 4794 Aj = Aj_new; 4795 } 4796 4797 if (nneg) { /* Discard heading entries with negative indices in perm[], as we'll access it from index 0 in MatSetValuesCOO */ 4798 PetscCount *perm_new; 4799 4800 PetscCall(PetscMalloc1(coo_n - nneg, &perm_new)); 4801 PetscCall(PetscArraycpy(perm_new, perm + nneg, coo_n - nneg)); 4802 PetscCall(PetscFree(perm)); 4803 perm = perm_new; 4804 } 4805 4806 PetscCall(MatGetRootType_Private(mat, &rtype)); 4807 PetscCall(PetscShmgetAllocateArray(nnz, sizeof(PetscScalar), (void **)&Aa)); 4808 PetscCall(PetscArrayzero(Aa, nnz)); 4809 PetscCall(MatSetSeqAIJWithArrays_private(PETSC_COMM_SELF, M, N, Ai, Aj, Aa, rtype, mat)); 4810 4811 seqaij->free_a = seqaij->free_ij = PETSC_TRUE; /* Let newmat own Ai, Aj and Aa */ 4812 4813 // Put the COO struct in a container and then attach that to the matrix 4814 PetscCall(PetscMalloc1(1, &coo)); 4815 PetscCall(PetscIntCast(nnz, &coo->nz)); 4816 coo->n = coo_n; 4817 coo->Atot = coo_n - nneg; // Annz is seqaij->nz, so no need to record that again 4818 coo->jmap = jmap; // of length nnz+1 4819 coo->perm = perm; 4820 PetscCall(PetscObjectContainerCompose((PetscObject)mat, "__PETSc_MatCOOStruct_Host", coo, MatCOOStructDestroy_SeqAIJ)); 4821 PetscFunctionReturn(PETSC_SUCCESS); 4822 } 4823 4824 static PetscErrorCode MatSetValuesCOO_SeqAIJ(Mat A, const PetscScalar v[], InsertMode imode) 4825 { 4826 Mat_SeqAIJ *aseq = (Mat_SeqAIJ *)A->data; 4827 PetscCount i, j, Annz = aseq->nz; 4828 PetscCount *perm, *jmap; 4829 PetscScalar *Aa; 4830 PetscContainer container; 4831 MatCOOStruct_SeqAIJ *coo; 4832 4833 PetscFunctionBegin; 4834 PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_MatCOOStruct_Host", (PetscObject *)&container)); 4835 PetscCheck(container, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not found MatCOOStruct on this matrix"); 4836 PetscCall(PetscContainerGetPointer(container, (void **)&coo)); 4837 perm = coo->perm; 4838 jmap = coo->jmap; 4839 PetscCall(MatSeqAIJGetArray(A, &Aa)); 4840 for (i = 0; i < Annz; i++) { 4841 PetscScalar sum = 0.0; 4842 for (j = jmap[i]; j < jmap[i + 1]; j++) sum += v[perm[j]]; 4843 Aa[i] = (imode == INSERT_VALUES ? 0.0 : Aa[i]) + sum; 4844 } 4845 PetscCall(MatSeqAIJRestoreArray(A, &Aa)); 4846 PetscFunctionReturn(PETSC_SUCCESS); 4847 } 4848 4849 #if defined(PETSC_HAVE_CUDA) 4850 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJCUSPARSE(Mat, MatType, MatReuse, Mat *); 4851 #endif 4852 #if defined(PETSC_HAVE_HIP) 4853 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJHIPSPARSE(Mat, MatType, MatReuse, Mat *); 4854 #endif 4855 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 4856 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJKokkos(Mat, MatType, MatReuse, Mat *); 4857 #endif 4858 4859 PETSC_EXTERN PetscErrorCode MatCreate_SeqAIJ(Mat B) 4860 { 4861 Mat_SeqAIJ *b; 4862 PetscMPIInt size; 4863 4864 PetscFunctionBegin; 4865 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)B), &size)); 4866 PetscCheck(size <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Comm must be of size 1"); 4867 4868 PetscCall(PetscNew(&b)); 4869 4870 B->data = (void *)b; 4871 B->ops[0] = MatOps_Values; 4872 if (B->sortedfull) B->ops->setvalues = MatSetValues_SeqAIJ_SortedFull; 4873 4874 b->row = NULL; 4875 b->col = NULL; 4876 b->icol = NULL; 4877 b->reallocs = 0; 4878 b->ignorezeroentries = PETSC_FALSE; 4879 b->roworiented = PETSC_TRUE; 4880 b->nonew = 0; 4881 b->diag = NULL; 4882 b->solve_work = NULL; 4883 B->spptr = NULL; 4884 b->saved_values = NULL; 4885 b->idiag = NULL; 4886 b->mdiag = NULL; 4887 b->ssor_work = NULL; 4888 b->omega = 1.0; 4889 b->fshift = 0.0; 4890 b->idiagvalid = PETSC_FALSE; 4891 b->ibdiagvalid = PETSC_FALSE; 4892 b->keepnonzeropattern = PETSC_FALSE; 4893 4894 PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATSEQAIJ)); 4895 #if defined(PETSC_HAVE_MATLAB) 4896 PetscCall(PetscObjectComposeFunction((PetscObject)B, "PetscMatlabEnginePut_C", MatlabEnginePut_SeqAIJ)); 4897 PetscCall(PetscObjectComposeFunction((PetscObject)B, "PetscMatlabEngineGet_C", MatlabEngineGet_SeqAIJ)); 4898 #endif 4899 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetColumnIndices_C", MatSeqAIJSetColumnIndices_SeqAIJ)); 4900 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatStoreValues_C", MatStoreValues_SeqAIJ)); 4901 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatRetrieveValues_C", MatRetrieveValues_SeqAIJ)); 4902 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqsbaij_C", MatConvert_SeqAIJ_SeqSBAIJ)); 4903 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqbaij_C", MatConvert_SeqAIJ_SeqBAIJ)); 4904 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijperm_C", MatConvert_SeqAIJ_SeqAIJPERM)); 4905 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijsell_C", MatConvert_SeqAIJ_SeqAIJSELL)); 4906 #if defined(PETSC_HAVE_MKL_SPARSE) 4907 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijmkl_C", MatConvert_SeqAIJ_SeqAIJMKL)); 4908 #endif 4909 #if defined(PETSC_HAVE_CUDA) 4910 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijcusparse_C", MatConvert_SeqAIJ_SeqAIJCUSPARSE)); 4911 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaijcusparse_seqaij_C", MatProductSetFromOptions_SeqAIJ)); 4912 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaijcusparse_C", MatProductSetFromOptions_SeqAIJ)); 4913 #endif 4914 #if defined(PETSC_HAVE_HIP) 4915 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijhipsparse_C", MatConvert_SeqAIJ_SeqAIJHIPSPARSE)); 4916 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaijhipsparse_seqaij_C", MatProductSetFromOptions_SeqAIJ)); 4917 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaijhipsparse_C", MatProductSetFromOptions_SeqAIJ)); 4918 #endif 4919 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 4920 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijkokkos_C", MatConvert_SeqAIJ_SeqAIJKokkos)); 4921 #endif 4922 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijcrl_C", MatConvert_SeqAIJ_SeqAIJCRL)); 4923 #if defined(PETSC_HAVE_ELEMENTAL) 4924 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_elemental_C", MatConvert_SeqAIJ_Elemental)); 4925 #endif 4926 #if defined(PETSC_HAVE_SCALAPACK) 4927 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_scalapack_C", MatConvert_AIJ_ScaLAPACK)); 4928 #endif 4929 #if defined(PETSC_HAVE_HYPRE) 4930 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_hypre_C", MatConvert_AIJ_HYPRE)); 4931 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_transpose_seqaij_seqaij_C", MatProductSetFromOptions_Transpose_AIJ_AIJ)); 4932 #endif 4933 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqdense_C", MatConvert_SeqAIJ_SeqDense)); 4934 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqsell_C", MatConvert_SeqAIJ_SeqSELL)); 4935 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_is_C", MatConvert_XAIJ_IS)); 4936 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsTranspose_C", MatIsTranspose_SeqAIJ)); 4937 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsHermitianTranspose_C", MatIsHermitianTranspose_SeqAIJ)); 4938 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetPreallocation_C", MatSeqAIJSetPreallocation_SeqAIJ)); 4939 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatResetPreallocation_C", MatResetPreallocation_SeqAIJ)); 4940 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatResetHash_C", MatResetHash_SeqAIJ)); 4941 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetPreallocationCSR_C", MatSeqAIJSetPreallocationCSR_SeqAIJ)); 4942 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatReorderForNonzeroDiagonal_C", MatReorderForNonzeroDiagonal_SeqAIJ)); 4943 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_is_seqaij_C", MatProductSetFromOptions_IS_XAIJ)); 4944 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqdense_seqaij_C", MatProductSetFromOptions_SeqDense_SeqAIJ)); 4945 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaij_C", MatProductSetFromOptions_SeqAIJ)); 4946 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJKron_C", MatSeqAIJKron_SeqAIJ)); 4947 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_SeqAIJ)); 4948 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSetValuesCOO_C", MatSetValuesCOO_SeqAIJ)); 4949 PetscCall(MatCreate_SeqAIJ_Inode(B)); 4950 PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATSEQAIJ)); 4951 PetscCall(MatSeqAIJSetTypeFromOptions(B)); /* this allows changing the matrix subtype to say MATSEQAIJPERM */ 4952 PetscFunctionReturn(PETSC_SUCCESS); 4953 } 4954 4955 /* 4956 Given a matrix generated with MatGetFactor() duplicates all the information in A into C 4957 */ 4958 PetscErrorCode MatDuplicateNoCreate_SeqAIJ(Mat C, Mat A, MatDuplicateOption cpvalues, PetscBool mallocmatspace) 4959 { 4960 Mat_SeqAIJ *c = (Mat_SeqAIJ *)C->data, *a = (Mat_SeqAIJ *)A->data; 4961 PetscInt m = A->rmap->n, i; 4962 4963 PetscFunctionBegin; 4964 PetscCheck(A->assembled || cpvalues == MAT_DO_NOT_COPY_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot duplicate unassembled matrix"); 4965 4966 C->factortype = A->factortype; 4967 c->row = NULL; 4968 c->col = NULL; 4969 c->icol = NULL; 4970 c->reallocs = 0; 4971 c->diagonaldense = a->diagonaldense; 4972 4973 C->assembled = A->assembled; 4974 4975 if (A->preallocated) { 4976 PetscCall(PetscLayoutReference(A->rmap, &C->rmap)); 4977 PetscCall(PetscLayoutReference(A->cmap, &C->cmap)); 4978 4979 if (!A->hash_active) { 4980 PetscCall(PetscMalloc1(m, &c->imax)); 4981 PetscCall(PetscMemcpy(c->imax, a->imax, m * sizeof(PetscInt))); 4982 PetscCall(PetscMalloc1(m, &c->ilen)); 4983 PetscCall(PetscMemcpy(c->ilen, a->ilen, m * sizeof(PetscInt))); 4984 4985 /* allocate the matrix space */ 4986 if (mallocmatspace) { 4987 PetscCall(PetscShmgetAllocateArray(a->i[m], sizeof(PetscScalar), (void **)&c->a)); 4988 PetscCall(PetscShmgetAllocateArray(a->i[m], sizeof(PetscInt), (void **)&c->j)); 4989 PetscCall(PetscShmgetAllocateArray(m + 1, sizeof(PetscInt), (void **)&c->i)); 4990 PetscCall(PetscArraycpy(c->i, a->i, m + 1)); 4991 c->free_a = PETSC_TRUE; 4992 c->free_ij = PETSC_TRUE; 4993 if (m > 0) { 4994 PetscCall(PetscArraycpy(c->j, a->j, a->i[m])); 4995 if (cpvalues == MAT_COPY_VALUES) { 4996 const PetscScalar *aa; 4997 4998 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 4999 PetscCall(PetscArraycpy(c->a, aa, a->i[m])); 5000 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 5001 } else { 5002 PetscCall(PetscArrayzero(c->a, a->i[m])); 5003 } 5004 } 5005 } 5006 C->preallocated = PETSC_TRUE; 5007 } else { 5008 PetscCheck(mallocmatspace, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Cannot malloc matrix memory from a non-preallocated matrix"); 5009 PetscCall(MatSetUp(C)); 5010 } 5011 5012 c->ignorezeroentries = a->ignorezeroentries; 5013 c->roworiented = a->roworiented; 5014 c->nonew = a->nonew; 5015 if (a->diag) { 5016 PetscCall(PetscMalloc1(m + 1, &c->diag)); 5017 PetscCall(PetscMemcpy(c->diag, a->diag, m * sizeof(PetscInt))); 5018 } else c->diag = NULL; 5019 5020 c->solve_work = NULL; 5021 c->saved_values = NULL; 5022 c->idiag = NULL; 5023 c->ssor_work = NULL; 5024 c->keepnonzeropattern = a->keepnonzeropattern; 5025 5026 c->rmax = a->rmax; 5027 c->nz = a->nz; 5028 c->maxnz = a->nz; /* Since we allocate exactly the right amount */ 5029 5030 c->compressedrow.use = a->compressedrow.use; 5031 c->compressedrow.nrows = a->compressedrow.nrows; 5032 if (a->compressedrow.use) { 5033 i = a->compressedrow.nrows; 5034 PetscCall(PetscMalloc2(i + 1, &c->compressedrow.i, i, &c->compressedrow.rindex)); 5035 PetscCall(PetscArraycpy(c->compressedrow.i, a->compressedrow.i, i + 1)); 5036 PetscCall(PetscArraycpy(c->compressedrow.rindex, a->compressedrow.rindex, i)); 5037 } else { 5038 c->compressedrow.use = PETSC_FALSE; 5039 c->compressedrow.i = NULL; 5040 c->compressedrow.rindex = NULL; 5041 } 5042 c->nonzerorowcnt = a->nonzerorowcnt; 5043 C->nonzerostate = A->nonzerostate; 5044 5045 PetscCall(MatDuplicate_SeqAIJ_Inode(A, cpvalues, &C)); 5046 } 5047 PetscCall(PetscFunctionListDuplicate(((PetscObject)A)->qlist, &((PetscObject)C)->qlist)); 5048 PetscFunctionReturn(PETSC_SUCCESS); 5049 } 5050 5051 PetscErrorCode MatDuplicate_SeqAIJ(Mat A, MatDuplicateOption cpvalues, Mat *B) 5052 { 5053 PetscFunctionBegin; 5054 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B)); 5055 PetscCall(MatSetSizes(*B, A->rmap->n, A->cmap->n, A->rmap->n, A->cmap->n)); 5056 if (!(A->rmap->n % A->rmap->bs) && !(A->cmap->n % A->cmap->bs)) PetscCall(MatSetBlockSizesFromMats(*B, A, A)); 5057 PetscCall(MatSetType(*B, ((PetscObject)A)->type_name)); 5058 PetscCall(MatDuplicateNoCreate_SeqAIJ(*B, A, cpvalues, PETSC_TRUE)); 5059 PetscFunctionReturn(PETSC_SUCCESS); 5060 } 5061 5062 PetscErrorCode MatLoad_SeqAIJ(Mat newMat, PetscViewer viewer) 5063 { 5064 PetscBool isbinary, ishdf5; 5065 5066 PetscFunctionBegin; 5067 PetscValidHeaderSpecific(newMat, MAT_CLASSID, 1); 5068 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 5069 /* force binary viewer to load .info file if it has not yet done so */ 5070 PetscCall(PetscViewerSetUp(viewer)); 5071 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 5072 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 5073 if (isbinary) { 5074 PetscCall(MatLoad_SeqAIJ_Binary(newMat, viewer)); 5075 } else if (ishdf5) { 5076 #if defined(PETSC_HAVE_HDF5) 5077 PetscCall(MatLoad_AIJ_HDF5(newMat, viewer)); 5078 #else 5079 SETERRQ(PetscObjectComm((PetscObject)newMat), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 5080 #endif 5081 } else { 5082 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); 5083 } 5084 PetscFunctionReturn(PETSC_SUCCESS); 5085 } 5086 5087 PetscErrorCode MatLoad_SeqAIJ_Binary(Mat mat, PetscViewer viewer) 5088 { 5089 Mat_SeqAIJ *a = (Mat_SeqAIJ *)mat->data; 5090 PetscInt header[4], *rowlens, M, N, nz, sum, rows, cols, i; 5091 5092 PetscFunctionBegin; 5093 PetscCall(PetscViewerSetUp(viewer)); 5094 5095 /* read in matrix header */ 5096 PetscCall(PetscViewerBinaryRead(viewer, header, 4, NULL, PETSC_INT)); 5097 PetscCheck(header[0] == MAT_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a matrix object in file"); 5098 M = header[1]; 5099 N = header[2]; 5100 nz = header[3]; 5101 PetscCheck(M >= 0, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Matrix row size (%" PetscInt_FMT ") in file is negative", M); 5102 PetscCheck(N >= 0, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Matrix column size (%" PetscInt_FMT ") in file is negative", N); 5103 PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Matrix stored in special format on disk, cannot load as SeqAIJ"); 5104 5105 /* set block sizes from the viewer's .info file */ 5106 PetscCall(MatLoad_Binary_BlockSizes(mat, viewer)); 5107 /* set local and global sizes if not set already */ 5108 if (mat->rmap->n < 0) mat->rmap->n = M; 5109 if (mat->cmap->n < 0) mat->cmap->n = N; 5110 if (mat->rmap->N < 0) mat->rmap->N = M; 5111 if (mat->cmap->N < 0) mat->cmap->N = N; 5112 PetscCall(PetscLayoutSetUp(mat->rmap)); 5113 PetscCall(PetscLayoutSetUp(mat->cmap)); 5114 5115 /* check if the matrix sizes are correct */ 5116 PetscCall(MatGetSize(mat, &rows, &cols)); 5117 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); 5118 5119 /* read in row lengths */ 5120 PetscCall(PetscMalloc1(M, &rowlens)); 5121 PetscCall(PetscViewerBinaryRead(viewer, rowlens, M, NULL, PETSC_INT)); 5122 /* check if sum(rowlens) is same as nz */ 5123 sum = 0; 5124 for (i = 0; i < M; i++) sum += rowlens[i]; 5125 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); 5126 /* preallocate and check sizes */ 5127 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(mat, 0, rowlens)); 5128 PetscCall(MatGetSize(mat, &rows, &cols)); 5129 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); 5130 /* store row lengths */ 5131 PetscCall(PetscArraycpy(a->ilen, rowlens, M)); 5132 PetscCall(PetscFree(rowlens)); 5133 5134 /* fill in "i" row pointers */ 5135 a->i[0] = 0; 5136 for (i = 0; i < M; i++) a->i[i + 1] = a->i[i] + a->ilen[i]; 5137 /* read in "j" column indices */ 5138 PetscCall(PetscViewerBinaryRead(viewer, a->j, nz, NULL, PETSC_INT)); 5139 /* read in "a" nonzero values */ 5140 PetscCall(PetscViewerBinaryRead(viewer, a->a, nz, NULL, PETSC_SCALAR)); 5141 5142 PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY)); 5143 PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY)); 5144 PetscFunctionReturn(PETSC_SUCCESS); 5145 } 5146 5147 PetscErrorCode MatEqual_SeqAIJ(Mat A, Mat B, PetscBool *flg) 5148 { 5149 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *b = (Mat_SeqAIJ *)B->data; 5150 const PetscScalar *aa, *ba; 5151 #if defined(PETSC_USE_COMPLEX) 5152 PetscInt k; 5153 #endif 5154 5155 PetscFunctionBegin; 5156 /* If the matrix dimensions are not equal,or no of nonzeros */ 5157 if ((A->rmap->n != B->rmap->n) || (A->cmap->n != B->cmap->n) || (a->nz != b->nz)) { 5158 *flg = PETSC_FALSE; 5159 PetscFunctionReturn(PETSC_SUCCESS); 5160 } 5161 5162 /* if the a->i are the same */ 5163 PetscCall(PetscArraycmp(a->i, b->i, A->rmap->n + 1, flg)); 5164 if (!*flg) PetscFunctionReturn(PETSC_SUCCESS); 5165 5166 /* if a->j are the same */ 5167 PetscCall(PetscArraycmp(a->j, b->j, a->nz, flg)); 5168 if (!*flg) PetscFunctionReturn(PETSC_SUCCESS); 5169 5170 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 5171 PetscCall(MatSeqAIJGetArrayRead(B, &ba)); 5172 /* if a->a are the same */ 5173 #if defined(PETSC_USE_COMPLEX) 5174 for (k = 0; k < a->nz; k++) { 5175 if (PetscRealPart(aa[k]) != PetscRealPart(ba[k]) || PetscImaginaryPart(aa[k]) != PetscImaginaryPart(ba[k])) { 5176 *flg = PETSC_FALSE; 5177 PetscFunctionReturn(PETSC_SUCCESS); 5178 } 5179 } 5180 #else 5181 PetscCall(PetscArraycmp(aa, ba, a->nz, flg)); 5182 #endif 5183 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 5184 PetscCall(MatSeqAIJRestoreArrayRead(B, &ba)); 5185 PetscFunctionReturn(PETSC_SUCCESS); 5186 } 5187 5188 /*@ 5189 MatCreateSeqAIJWithArrays - Creates an sequential `MATSEQAIJ` matrix using matrix elements (in CSR format) 5190 provided by the user. 5191 5192 Collective 5193 5194 Input Parameters: 5195 + comm - must be an MPI communicator of size 1 5196 . m - number of rows 5197 . n - number of columns 5198 . i - row indices; that is i[0] = 0, i[row] = i[row-1] + number of elements in that row of the matrix 5199 . j - column indices 5200 - a - matrix values 5201 5202 Output Parameter: 5203 . mat - the matrix 5204 5205 Level: intermediate 5206 5207 Notes: 5208 The `i`, `j`, and `a` arrays are not copied by this routine, the user must free these arrays 5209 once the matrix is destroyed and not before 5210 5211 You cannot set new nonzero locations into this matrix, that will generate an error. 5212 5213 The `i` and `j` indices are 0 based 5214 5215 The format which is used for the sparse matrix input, is equivalent to a 5216 row-major ordering.. i.e for the following matrix, the input data expected is 5217 as shown 5218 .vb 5219 1 0 0 5220 2 0 3 5221 4 5 6 5222 5223 i = {0,1,3,6} [size = nrow+1 = 3+1] 5224 j = {0,0,2,0,1,2} [size = 6]; values must be sorted for each row 5225 v = {1,2,3,4,5,6} [size = 6] 5226 .ve 5227 5228 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MatCreateMPIAIJWithArrays()`, `MatMPIAIJSetPreallocationCSR()` 5229 @*/ 5230 PetscErrorCode MatCreateSeqAIJWithArrays(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt i[], PetscInt j[], PetscScalar a[], Mat *mat) 5231 { 5232 PetscInt ii; 5233 Mat_SeqAIJ *aij; 5234 PetscInt jj; 5235 5236 PetscFunctionBegin; 5237 PetscCheck(m <= 0 || i[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "i (row indices) must start with 0"); 5238 PetscCall(MatCreate(comm, mat)); 5239 PetscCall(MatSetSizes(*mat, m, n, m, n)); 5240 /* PetscCall(MatSetBlockSizes(*mat,,)); */ 5241 PetscCall(MatSetType(*mat, MATSEQAIJ)); 5242 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*mat, MAT_SKIP_ALLOCATION, NULL)); 5243 aij = (Mat_SeqAIJ *)(*mat)->data; 5244 PetscCall(PetscMalloc1(m, &aij->imax)); 5245 PetscCall(PetscMalloc1(m, &aij->ilen)); 5246 5247 aij->i = i; 5248 aij->j = j; 5249 aij->a = a; 5250 aij->nonew = -1; /*this indicates that inserting a new value in the matrix that generates a new nonzero is an error*/ 5251 aij->free_a = PETSC_FALSE; 5252 aij->free_ij = PETSC_FALSE; 5253 5254 for (ii = 0, aij->nonzerorowcnt = 0, aij->rmax = 0; ii < m; ii++) { 5255 aij->ilen[ii] = aij->imax[ii] = i[ii + 1] - i[ii]; 5256 if (PetscDefined(USE_DEBUG)) { 5257 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]); 5258 for (jj = i[ii] + 1; jj < i[ii + 1]; jj++) { 5259 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); 5260 PetscCheck(j[jj] != j[jj - 1], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column entry number %" PetscInt_FMT " (actual column %" PetscInt_FMT ") in row %" PetscInt_FMT " is identical to previous entry", jj - i[ii], j[jj], ii); 5261 } 5262 } 5263 } 5264 if (PetscDefined(USE_DEBUG)) { 5265 for (ii = 0; ii < aij->i[m]; ii++) { 5266 PetscCheck(j[ii] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative column index at location = %" PetscInt_FMT " index = %" PetscInt_FMT, ii, j[ii]); 5267 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); 5268 } 5269 } 5270 5271 PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY)); 5272 PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY)); 5273 PetscFunctionReturn(PETSC_SUCCESS); 5274 } 5275 5276 /*@ 5277 MatCreateSeqAIJFromTriple - Creates an sequential `MATSEQAIJ` matrix using matrix elements (in COO format) 5278 provided by the user. 5279 5280 Collective 5281 5282 Input Parameters: 5283 + comm - must be an MPI communicator of size 1 5284 . m - number of rows 5285 . n - number of columns 5286 . i - row indices 5287 . j - column indices 5288 . a - matrix values 5289 . nz - number of nonzeros 5290 - idx - if the `i` and `j` indices start with 1 use `PETSC_TRUE` otherwise use `PETSC_FALSE` 5291 5292 Output Parameter: 5293 . mat - the matrix 5294 5295 Level: intermediate 5296 5297 Example: 5298 For the following matrix, the input data expected is as shown (using 0 based indexing) 5299 .vb 5300 1 0 0 5301 2 0 3 5302 4 5 6 5303 5304 i = {0,1,1,2,2,2} 5305 j = {0,0,2,0,1,2} 5306 v = {1,2,3,4,5,6} 5307 .ve 5308 5309 Note: 5310 Instead of using this function, users should also consider `MatSetPreallocationCOO()` and `MatSetValuesCOO()`, which allow repeated or remote entries, 5311 and are particularly useful in iterative applications. 5312 5313 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MatCreateSeqAIJWithArrays()`, `MatMPIAIJSetPreallocationCSR()`, `MatSetValuesCOO()`, `MatSetPreallocationCOO()` 5314 @*/ 5315 PetscErrorCode MatCreateSeqAIJFromTriple(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt i[], PetscInt j[], PetscScalar a[], Mat *mat, PetscCount nz, PetscBool idx) 5316 { 5317 PetscInt ii, *nnz, one = 1, row, col; 5318 5319 PetscFunctionBegin; 5320 PetscCall(PetscCalloc1(m, &nnz)); 5321 for (ii = 0; ii < nz; ii++) nnz[i[ii] - !!idx] += 1; 5322 PetscCall(MatCreate(comm, mat)); 5323 PetscCall(MatSetSizes(*mat, m, n, m, n)); 5324 PetscCall(MatSetType(*mat, MATSEQAIJ)); 5325 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*mat, 0, nnz)); 5326 for (ii = 0; ii < nz; ii++) { 5327 if (idx) { 5328 row = i[ii] - 1; 5329 col = j[ii] - 1; 5330 } else { 5331 row = i[ii]; 5332 col = j[ii]; 5333 } 5334 PetscCall(MatSetValues(*mat, one, &row, one, &col, &a[ii], ADD_VALUES)); 5335 } 5336 PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY)); 5337 PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY)); 5338 PetscCall(PetscFree(nnz)); 5339 PetscFunctionReturn(PETSC_SUCCESS); 5340 } 5341 5342 PetscErrorCode MatSeqAIJInvalidateDiagonal(Mat A) 5343 { 5344 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 5345 5346 PetscFunctionBegin; 5347 a->idiagvalid = PETSC_FALSE; 5348 a->ibdiagvalid = PETSC_FALSE; 5349 5350 PetscCall(MatSeqAIJInvalidateDiagonal_Inode(A)); 5351 PetscFunctionReturn(PETSC_SUCCESS); 5352 } 5353 5354 PetscErrorCode MatCreateMPIMatConcatenateSeqMat_SeqAIJ(MPI_Comm comm, Mat inmat, PetscInt n, MatReuse scall, Mat *outmat) 5355 { 5356 PetscFunctionBegin; 5357 PetscCall(MatCreateMPIMatConcatenateSeqMat_MPIAIJ(comm, inmat, n, scall, outmat)); 5358 PetscFunctionReturn(PETSC_SUCCESS); 5359 } 5360 5361 /* 5362 Permute A into C's *local* index space using rowemb,colemb. 5363 The embedding are supposed to be injections and the above implies that the range of rowemb is a subset 5364 of [0,m), colemb is in [0,n). 5365 If pattern == DIFFERENT_NONZERO_PATTERN, C is preallocated according to A. 5366 */ 5367 PetscErrorCode MatSetSeqMat_SeqAIJ(Mat C, IS rowemb, IS colemb, MatStructure pattern, Mat B) 5368 { 5369 /* If making this function public, change the error returned in this function away from _PLIB. */ 5370 Mat_SeqAIJ *Baij; 5371 PetscBool seqaij; 5372 PetscInt m, n, *nz, i, j, count; 5373 PetscScalar v; 5374 const PetscInt *rowindices, *colindices; 5375 5376 PetscFunctionBegin; 5377 if (!B) PetscFunctionReturn(PETSC_SUCCESS); 5378 /* Check to make sure the target matrix (and embeddings) are compatible with C and each other. */ 5379 PetscCall(PetscObjectBaseTypeCompare((PetscObject)B, MATSEQAIJ, &seqaij)); 5380 PetscCheck(seqaij, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is of wrong type"); 5381 if (rowemb) { 5382 PetscCall(ISGetLocalSize(rowemb, &m)); 5383 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); 5384 } else { 5385 PetscCheck(C->rmap->n == B->rmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is row-incompatible with the target matrix"); 5386 } 5387 if (colemb) { 5388 PetscCall(ISGetLocalSize(colemb, &n)); 5389 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); 5390 } else { 5391 PetscCheck(C->cmap->n == B->cmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is col-incompatible with the target matrix"); 5392 } 5393 5394 Baij = (Mat_SeqAIJ *)B->data; 5395 if (pattern == DIFFERENT_NONZERO_PATTERN) { 5396 PetscCall(PetscMalloc1(B->rmap->n, &nz)); 5397 for (i = 0; i < B->rmap->n; i++) nz[i] = Baij->i[i + 1] - Baij->i[i]; 5398 PetscCall(MatSeqAIJSetPreallocation(C, 0, nz)); 5399 PetscCall(PetscFree(nz)); 5400 } 5401 if (pattern == SUBSET_NONZERO_PATTERN) PetscCall(MatZeroEntries(C)); 5402 count = 0; 5403 rowindices = NULL; 5404 colindices = NULL; 5405 if (rowemb) PetscCall(ISGetIndices(rowemb, &rowindices)); 5406 if (colemb) PetscCall(ISGetIndices(colemb, &colindices)); 5407 for (i = 0; i < B->rmap->n; i++) { 5408 PetscInt row; 5409 row = i; 5410 if (rowindices) row = rowindices[i]; 5411 for (j = Baij->i[i]; j < Baij->i[i + 1]; j++) { 5412 PetscInt col; 5413 col = Baij->j[count]; 5414 if (colindices) col = colindices[col]; 5415 v = Baij->a[count]; 5416 PetscCall(MatSetValues(C, 1, &row, 1, &col, &v, INSERT_VALUES)); 5417 ++count; 5418 } 5419 } 5420 /* FIXME: set C's nonzerostate correctly. */ 5421 /* Assembly for C is necessary. */ 5422 C->preallocated = PETSC_TRUE; 5423 C->assembled = PETSC_TRUE; 5424 C->was_assembled = PETSC_FALSE; 5425 PetscFunctionReturn(PETSC_SUCCESS); 5426 } 5427 5428 PetscErrorCode MatEliminateZeros_SeqAIJ(Mat A, PetscBool keep) 5429 { 5430 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 5431 MatScalar *aa = a->a; 5432 PetscInt m = A->rmap->n, fshift = 0, fshift_prev = 0, i, k; 5433 PetscInt *ailen = a->ilen, *imax = a->imax, *ai = a->i, *aj = a->j, rmax = 0; 5434 5435 PetscFunctionBegin; 5436 PetscCheck(A->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot eliminate zeros for unassembled matrix"); 5437 if (m) rmax = ailen[0]; /* determine row with most nonzeros */ 5438 for (i = 1; i <= m; i++) { 5439 /* move each nonzero entry back by the amount of zero slots (fshift) before it*/ 5440 for (k = ai[i - 1]; k < ai[i]; k++) { 5441 if (aa[k] == 0 && (aj[k] != i - 1 || !keep)) fshift++; 5442 else { 5443 if (aa[k] == 0 && aj[k] == i - 1) PetscCall(PetscInfo(A, "Keep the diagonal zero at row %" PetscInt_FMT "\n", i - 1)); 5444 aa[k - fshift] = aa[k]; 5445 aj[k - fshift] = aj[k]; 5446 } 5447 } 5448 ai[i - 1] -= fshift_prev; // safe to update ai[i-1] now since it will not be used in the next iteration 5449 fshift_prev = fshift; 5450 /* reset ilen and imax for each row */ 5451 ailen[i - 1] = imax[i - 1] = ai[i] - fshift - ai[i - 1]; 5452 a->nonzerorowcnt += ((ai[i] - fshift - ai[i - 1]) > 0); 5453 rmax = PetscMax(rmax, ailen[i - 1]); 5454 } 5455 if (fshift) { 5456 if (m) { 5457 ai[m] -= fshift; 5458 a->nz = ai[m]; 5459 } 5460 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)); 5461 A->nonzerostate++; 5462 A->info.nz_unneeded += (PetscReal)fshift; 5463 a->rmax = rmax; 5464 if (a->inode.use && a->inode.checked) PetscCall(MatSeqAIJCheckInode(A)); 5465 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 5466 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 5467 } 5468 PetscFunctionReturn(PETSC_SUCCESS); 5469 } 5470 5471 PetscFunctionList MatSeqAIJList = NULL; 5472 5473 /*@ 5474 MatSeqAIJSetType - Converts a `MATSEQAIJ` matrix to a subtype 5475 5476 Collective 5477 5478 Input Parameters: 5479 + mat - the matrix object 5480 - matype - matrix type 5481 5482 Options Database Key: 5483 . -mat_seqaij_type <method> - for example seqaijcrl 5484 5485 Level: intermediate 5486 5487 .seealso: [](ch_matrices), `Mat`, `PCSetType()`, `VecSetType()`, `MatCreate()`, `MatType` 5488 @*/ 5489 PetscErrorCode MatSeqAIJSetType(Mat mat, MatType matype) 5490 { 5491 PetscBool sametype; 5492 PetscErrorCode (*r)(Mat, MatType, MatReuse, Mat *); 5493 5494 PetscFunctionBegin; 5495 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 5496 PetscCall(PetscObjectTypeCompare((PetscObject)mat, matype, &sametype)); 5497 if (sametype) PetscFunctionReturn(PETSC_SUCCESS); 5498 5499 PetscCall(PetscFunctionListFind(MatSeqAIJList, matype, &r)); 5500 PetscCheck(r, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown Mat type given: %s", matype); 5501 PetscCall((*r)(mat, matype, MAT_INPLACE_MATRIX, &mat)); 5502 PetscFunctionReturn(PETSC_SUCCESS); 5503 } 5504 5505 /*@C 5506 MatSeqAIJRegister - - Adds a new sub-matrix type for sequential `MATSEQAIJ` matrices 5507 5508 Not Collective, No Fortran Support 5509 5510 Input Parameters: 5511 + sname - name of a new user-defined matrix type, for example `MATSEQAIJCRL` 5512 - function - routine to convert to subtype 5513 5514 Level: advanced 5515 5516 Notes: 5517 `MatSeqAIJRegister()` may be called multiple times to add several user-defined solvers. 5518 5519 Then, your matrix can be chosen with the procedural interface at runtime via the option 5520 $ -mat_seqaij_type my_mat 5521 5522 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJRegisterAll()` 5523 @*/ 5524 PetscErrorCode MatSeqAIJRegister(const char sname[], PetscErrorCode (*function)(Mat, MatType, MatReuse, Mat *)) 5525 { 5526 PetscFunctionBegin; 5527 PetscCall(MatInitializePackage()); 5528 PetscCall(PetscFunctionListAdd(&MatSeqAIJList, sname, function)); 5529 PetscFunctionReturn(PETSC_SUCCESS); 5530 } 5531 5532 PetscBool MatSeqAIJRegisterAllCalled = PETSC_FALSE; 5533 5534 /*@C 5535 MatSeqAIJRegisterAll - Registers all of the matrix subtypes of `MATSSEQAIJ` 5536 5537 Not Collective 5538 5539 Level: advanced 5540 5541 Note: 5542 This registers the versions of `MATSEQAIJ` for GPUs 5543 5544 .seealso: [](ch_matrices), `Mat`, `MatRegisterAll()`, `MatSeqAIJRegister()` 5545 @*/ 5546 PetscErrorCode MatSeqAIJRegisterAll(void) 5547 { 5548 PetscFunctionBegin; 5549 if (MatSeqAIJRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS); 5550 MatSeqAIJRegisterAllCalled = PETSC_TRUE; 5551 5552 PetscCall(MatSeqAIJRegister(MATSEQAIJCRL, MatConvert_SeqAIJ_SeqAIJCRL)); 5553 PetscCall(MatSeqAIJRegister(MATSEQAIJPERM, MatConvert_SeqAIJ_SeqAIJPERM)); 5554 PetscCall(MatSeqAIJRegister(MATSEQAIJSELL, MatConvert_SeqAIJ_SeqAIJSELL)); 5555 #if defined(PETSC_HAVE_MKL_SPARSE) 5556 PetscCall(MatSeqAIJRegister(MATSEQAIJMKL, MatConvert_SeqAIJ_SeqAIJMKL)); 5557 #endif 5558 #if defined(PETSC_HAVE_CUDA) 5559 PetscCall(MatSeqAIJRegister(MATSEQAIJCUSPARSE, MatConvert_SeqAIJ_SeqAIJCUSPARSE)); 5560 #endif 5561 #if defined(PETSC_HAVE_HIP) 5562 PetscCall(MatSeqAIJRegister(MATSEQAIJHIPSPARSE, MatConvert_SeqAIJ_SeqAIJHIPSPARSE)); 5563 #endif 5564 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 5565 PetscCall(MatSeqAIJRegister(MATSEQAIJKOKKOS, MatConvert_SeqAIJ_SeqAIJKokkos)); 5566 #endif 5567 #if defined(PETSC_HAVE_VIENNACL) && defined(PETSC_HAVE_VIENNACL_NO_CUDA) 5568 PetscCall(MatSeqAIJRegister(MATMPIAIJVIENNACL, MatConvert_SeqAIJ_SeqAIJViennaCL)); 5569 #endif 5570 PetscFunctionReturn(PETSC_SUCCESS); 5571 } 5572 5573 /* 5574 Special version for direct calls from Fortran 5575 */ 5576 #if defined(PETSC_HAVE_FORTRAN_CAPS) 5577 #define matsetvaluesseqaij_ MATSETVALUESSEQAIJ 5578 #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE) 5579 #define matsetvaluesseqaij_ matsetvaluesseqaij 5580 #endif 5581 5582 /* Change these macros so can be used in void function */ 5583 5584 /* Change these macros so can be used in void function */ 5585 /* Identical to PetscCallVoid, except it assigns to *_ierr */ 5586 #undef PetscCall 5587 #define PetscCall(...) \ 5588 do { \ 5589 PetscErrorCode ierr_msv_mpiaij = __VA_ARGS__; \ 5590 if (PetscUnlikely(ierr_msv_mpiaij)) { \ 5591 *_ierr = PetscError(PETSC_COMM_SELF, __LINE__, PETSC_FUNCTION_NAME, __FILE__, ierr_msv_mpiaij, PETSC_ERROR_REPEAT, " "); \ 5592 return; \ 5593 } \ 5594 } while (0) 5595 5596 #undef SETERRQ 5597 #define SETERRQ(comm, ierr, ...) \ 5598 do { \ 5599 *_ierr = PetscError(comm, __LINE__, PETSC_FUNCTION_NAME, __FILE__, ierr, PETSC_ERROR_INITIAL, __VA_ARGS__); \ 5600 return; \ 5601 } while (0) 5602 5603 PETSC_EXTERN void matsetvaluesseqaij_(Mat *AA, PetscInt *mm, const PetscInt im[], PetscInt *nn, const PetscInt in[], const PetscScalar v[], InsertMode *isis, PetscErrorCode *_ierr) 5604 { 5605 Mat A = *AA; 5606 PetscInt m = *mm, n = *nn; 5607 InsertMode is = *isis; 5608 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 5609 PetscInt *rp, k, low, high, t, ii, row, nrow, i, col, l, rmax, N; 5610 PetscInt *imax, *ai, *ailen; 5611 PetscInt *aj, nonew = a->nonew, lastcol = -1; 5612 MatScalar *ap, value, *aa; 5613 PetscBool ignorezeroentries = a->ignorezeroentries; 5614 PetscBool roworiented = a->roworiented; 5615 5616 PetscFunctionBegin; 5617 MatCheckPreallocated(A, 1); 5618 imax = a->imax; 5619 ai = a->i; 5620 ailen = a->ilen; 5621 aj = a->j; 5622 aa = a->a; 5623 5624 for (k = 0; k < m; k++) { /* loop over added rows */ 5625 row = im[k]; 5626 if (row < 0) continue; 5627 PetscCheck(row < A->rmap->n, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large"); 5628 rp = aj + ai[row]; 5629 ap = aa + ai[row]; 5630 rmax = imax[row]; 5631 nrow = ailen[row]; 5632 low = 0; 5633 high = nrow; 5634 for (l = 0; l < n; l++) { /* loop over added columns */ 5635 if (in[l] < 0) continue; 5636 PetscCheck(in[l] < A->cmap->n, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Column too large"); 5637 col = in[l]; 5638 if (roworiented) value = v[l + k * n]; 5639 else value = v[k + l * m]; 5640 5641 if (value == 0.0 && ignorezeroentries && (is == ADD_VALUES)) continue; 5642 5643 if (col <= lastcol) low = 0; 5644 else high = nrow; 5645 lastcol = col; 5646 while (high - low > 5) { 5647 t = (low + high) / 2; 5648 if (rp[t] > col) high = t; 5649 else low = t; 5650 } 5651 for (i = low; i < high; i++) { 5652 if (rp[i] > col) break; 5653 if (rp[i] == col) { 5654 if (is == ADD_VALUES) ap[i] += value; 5655 else ap[i] = value; 5656 goto noinsert; 5657 } 5658 } 5659 if (value == 0.0 && ignorezeroentries) goto noinsert; 5660 if (nonew == 1) goto noinsert; 5661 PetscCheck(nonew != -1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero in the matrix"); 5662 MatSeqXAIJReallocateAIJ(A, A->rmap->n, 1, nrow, row, col, rmax, aa, ai, aj, rp, ap, imax, nonew, MatScalar); 5663 N = nrow++ - 1; 5664 a->nz++; 5665 high++; 5666 /* shift up all the later entries in this row */ 5667 for (ii = N; ii >= i; ii--) { 5668 rp[ii + 1] = rp[ii]; 5669 ap[ii + 1] = ap[ii]; 5670 } 5671 rp[i] = col; 5672 ap[i] = value; 5673 noinsert:; 5674 low = i + 1; 5675 } 5676 ailen[row] = nrow; 5677 } 5678 PetscFunctionReturnVoid(); 5679 } 5680 /* Undefining these here since they were redefined from their original definition above! No 5681 * other PETSc functions should be defined past this point, as it is impossible to recover the 5682 * original definitions */ 5683 #undef PetscCall 5684 #undef SETERRQ 5685