/* Defines transpose routines for SeqAIJ matrices. */ #include <../src/mat/impls/aij/seq/aij.h> /* The symbolic and full transpose versions share several similar code blocks but the macros to reuse the code would be confusing and ugly */ PetscErrorCode MatTransposeSymbolic_SeqAIJ(Mat A, Mat *B) { PetscInt i, j, anzj; Mat At; Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *at; PetscInt an = A->cmap->N, am = A->rmap->N; PetscInt *ati, *atj, *atfill, *ai = a->i, *aj = a->j; PetscFunctionBegin; /* Allocate space for symbolic transpose info and work array */ PetscCall(PetscCalloc1(an + 1, &ati)); PetscCall(PetscMalloc1(ai[am], &atj)); /* Walk through aj and count ## of non-zeros in each row of A^T. */ /* Note: offset by 1 for fast conversion into csr format. */ for (i = 0; i < ai[am]; i++) ati[aj[i] + 1] += 1; /* Form ati for csr format of A^T. */ for (i = 0; i < an; i++) ati[i + 1] += ati[i]; /* Copy ati into atfill so we have locations of the next free space in atj */ PetscCall(PetscMalloc1(an, &atfill)); PetscCall(PetscArraycpy(atfill, ati, an)); /* Walk through A row-wise and mark nonzero entries of A^T. */ for (i = 0; i < am; i++) { anzj = ai[i + 1] - ai[i]; for (j = 0; j < anzj; j++) { atj[atfill[*aj]] = i; atfill[*aj++] += 1; } } PetscCall(PetscFree(atfill)); PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), an, am, ati, atj, NULL, &At)); PetscCall(MatSetBlockSizes(At, A->cmap->bs, A->rmap->bs)); PetscCall(MatSetType(At, ((PetscObject)A)->type_name)); at = (Mat_SeqAIJ *)At->data; at->free_a = PETSC_FALSE; at->free_ij = PETSC_TRUE; at->nonew = 0; at->maxnz = ati[an]; *B = At; PetscFunctionReturn(PETSC_SUCCESS); } PetscErrorCode MatTranspose_SeqAIJ(Mat A, MatReuse reuse, Mat *B) { PetscInt i, j, anzj; Mat At; Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *at; PetscInt an = A->cmap->N, am = A->rmap->N; PetscInt *ati, *atj, *atfill, *ai = a->i, *aj = a->j; MatScalar *ata; const MatScalar *aa, *av; PetscContainer rB; MatParentState *rb; PetscBool nonzerochange = PETSC_FALSE; PetscFunctionBegin; if (reuse == MAT_REUSE_MATRIX) { PetscCall(PetscObjectQuery((PetscObject)*B, "MatTransposeParent", (PetscObject *)&rB)); PetscCheck(rB, PetscObjectComm((PetscObject)*B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from call to MatTranspose()"); PetscCall(PetscContainerGetPointer(rB, (void **)&rb)); if (rb->nonzerostate != A->nonzerostate) nonzerochange = PETSC_TRUE; } PetscCall(MatSeqAIJGetArrayRead(A, &av)); aa = av; if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX || nonzerochange) { /* Allocate space for symbolic transpose info and work array */ PetscCall(PetscCalloc1(an + 1, &ati)); PetscCall(PetscMalloc1(ai[am], &atj)); /* Walk through aj and count ## of non-zeros in each row of A^T. */ /* Note: offset by 1 for fast conversion into csr format. */ for (i = 0; i < ai[am]; i++) ati[aj[i] + 1] += 1; /* Form ati for csr format of A^T. */ for (i = 0; i < an; i++) ati[i + 1] += ati[i]; PetscCall(PetscMalloc1(ai[am], &ata)); } else { Mat_SeqAIJ *sub_B = (Mat_SeqAIJ *)(*B)->data; ati = sub_B->i; atj = sub_B->j; ata = sub_B->a; At = *B; } /* Copy ati into atfill so we have locations of the next free space in atj */ PetscCall(PetscMalloc1(an, &atfill)); PetscCall(PetscArraycpy(atfill, ati, an)); /* Walk through A row-wise and mark nonzero entries of A^T. */ if (aa) { for (i = 0; i < am; i++) { anzj = ai[i + 1] - ai[i]; for (j = 0; j < anzj; j++) { atj[atfill[*aj]] = i; ata[atfill[*aj]] = *aa++; atfill[*aj++] += 1; } } } else { for (i = 0; i < am; i++) { anzj = ai[i + 1] - ai[i]; for (j = 0; j < anzj; j++) { atj[atfill[*aj]] = i; atfill[*aj++] += 1; } } } PetscCall(PetscFree(atfill)); PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); if (reuse == MAT_REUSE_MATRIX) PetscCall(PetscObjectStateIncrease((PetscObject)*B)); if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX || nonzerochange) { PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), an, am, ati, atj, ata, &At)); PetscCall(MatSetBlockSizes(At, A->cmap->bs, A->rmap->bs)); PetscCall(MatSetType(At, ((PetscObject)A)->type_name)); at = (Mat_SeqAIJ *)At->data; at->free_a = PETSC_TRUE; at->free_ij = PETSC_TRUE; at->nonew = 0; at->maxnz = ati[an]; } if (reuse == MAT_INITIAL_MATRIX || (reuse == MAT_REUSE_MATRIX && !nonzerochange)) { *B = At; } else if (nonzerochange) { PetscCall(MatHeaderMerge(*B, &At)); PetscCall(MatTransposeSetPrecursor(A, *B)); } else if (reuse == MAT_INPLACE_MATRIX) { PetscCall(MatHeaderMerge(A, &At)); } PetscFunctionReturn(PETSC_SUCCESS); } /* Get symbolic matrix nonzero structure of a submatrix of A, A[rstart:rend,:], */ PetscErrorCode MatGetSymbolicTransposeReduced_SeqAIJ(Mat A, PetscInt rstart, PetscInt rend, PetscInt *Ati[], PetscInt *Atj[]) { PetscInt i, j, anzj; Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; PetscInt an = A->cmap->N; PetscInt *ati, *atj, *atfill, *ai = a->i, *aj = a->j, am = ai[rend] - ai[rstart]; PetscFunctionBegin; PetscCall(PetscLogEventBegin(MAT_Getsymtransreduced, A, 0, 0, 0)); /* Allocate space for symbolic transpose info and work array */ PetscCall(PetscCalloc1(an + 1, &ati)); PetscCall(PetscMalloc1(am + 1, &atj)); /* Walk through aj and count ## of non-zeros in each row of A^T. */ /* Note: offset by 1 for fast conversion into csr format. */ for (i = ai[rstart]; i < ai[rend]; i++) ati[aj[i] + 1] += 1; /* Form ati for csr format of A^T. */ for (i = 0; i < an; i++) ati[i + 1] += ati[i]; /* Copy ati into atfill so we have locations of the next free space in atj */ PetscCall(PetscMalloc1(an + 1, &atfill)); PetscCall(PetscArraycpy(atfill, ati, an)); /* Walk through A row-wise and mark nonzero entries of A^T. */ aj = PetscSafePointerPlusOffset(aj, ai[rstart]); for (i = rstart; i < rend; i++) { anzj = ai[i + 1] - ai[i]; for (j = 0; j < anzj; j++) { atj[atfill[*aj]] = i - rstart; atfill[*aj++] += 1; } } PetscCall(PetscFree(atfill)); *Ati = ati; *Atj = atj; PetscCall(PetscLogEventEnd(MAT_Getsymtransreduced, A, 0, 0, 0)); PetscFunctionReturn(PETSC_SUCCESS); } /* Returns the i and j arrays for a symbolic transpose, this is used internally within SeqAIJ code when the full symbolic matrix (which can be obtained with MatTransposeSymbolic() is not needed. MatRestoreSymbolicTranspose_SeqAIJ() should be used to free the arrays. */ PetscErrorCode MatGetSymbolicTranspose_SeqAIJ(Mat A, PetscInt *Ati[], PetscInt *Atj[]) { PetscFunctionBegin; PetscCall(MatGetSymbolicTransposeReduced_SeqAIJ(A, 0, A->rmap->N, Ati, Atj)); PetscFunctionReturn(PETSC_SUCCESS); } PetscErrorCode MatRestoreSymbolicTranspose_SeqAIJ(Mat A, PetscInt *ati[], PetscInt *atj[]) { PetscFunctionBegin; PetscCall(PetscFree(*ati)); PetscCall(PetscFree(*atj)); PetscFunctionReturn(PETSC_SUCCESS); }