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