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