1 2 /* 3 Defines transpose routines for SeqAIJ matrices. 4 */ 5 6 #include <../src/mat/impls/aij/seq/aij.h> 7 8 /* 9 The symbolic and full transpose versions share several similar code blocks but the macros to reuse the code would be confusing and ugly 10 */ 11 PetscErrorCode MatTransposeSymbolic_SeqAIJ(Mat A, Mat *B) { 12 PetscInt i, j, anzj; 13 Mat At; 14 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *at; 15 PetscInt an = A->cmap->N, am = A->rmap->N; 16 PetscInt *ati, *atj, *atfill, *ai = a->i, *aj = a->j; 17 18 PetscFunctionBegin; 19 /* Allocate space for symbolic transpose info and work array */ 20 PetscCall(PetscCalloc1(an + 1, &ati)); 21 PetscCall(PetscMalloc1(ai[am], &atj)); 22 23 /* Walk through aj and count ## of non-zeros in each row of A^T. */ 24 /* Note: offset by 1 for fast conversion into csr format. */ 25 for (i = 0; i < ai[am]; i++) ati[aj[i] + 1] += 1; 26 /* Form ati for csr format of A^T. */ 27 for (i = 0; i < an; i++) ati[i + 1] += ati[i]; 28 29 /* Copy ati into atfill so we have locations of the next free space in atj */ 30 PetscCall(PetscMalloc1(an, &atfill)); 31 PetscCall(PetscArraycpy(atfill, ati, an)); 32 33 /* Walk through A row-wise and mark nonzero entries of A^T. */ 34 for (i = 0; i < am; i++) { 35 anzj = ai[i + 1] - ai[i]; 36 for (j = 0; j < anzj; j++) { 37 atj[atfill[*aj]] = i; 38 atfill[*aj++] += 1; 39 } 40 } 41 PetscCall(PetscFree(atfill)); 42 43 PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), an, am, ati, atj, NULL, &At)); 44 PetscCall(MatSetBlockSizes(At, PetscAbs(A->cmap->bs), PetscAbs(A->rmap->bs))); 45 PetscCall(MatSetType(At, ((PetscObject)A)->type_name)); 46 at = (Mat_SeqAIJ *)At->data; 47 at->free_a = PETSC_FALSE; 48 at->free_ij = PETSC_TRUE; 49 at->nonew = 0; 50 at->maxnz = ati[an]; 51 *B = At; 52 PetscFunctionReturn(0); 53 } 54 55 PetscErrorCode MatTranspose_SeqAIJ(Mat A, MatReuse reuse, Mat *B) { 56 PetscInt i, j, anzj; 57 Mat At; 58 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *at; 59 PetscInt an = A->cmap->N, am = A->rmap->N; 60 PetscInt *ati, *atj, *atfill, *ai = a->i, *aj = a->j; 61 MatScalar *ata; 62 const MatScalar *aa, *av; 63 PetscContainer rB; 64 MatParentState *rb; 65 PetscBool nonzerochange = PETSC_FALSE; 66 67 PetscFunctionBegin; 68 if (reuse == MAT_REUSE_MATRIX) { 69 PetscCall(PetscObjectQuery((PetscObject)*B, "MatTransposeParent", (PetscObject *)&rB)); 70 PetscCheck(rB, PetscObjectComm((PetscObject)*B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from call to MatTranspose()"); 71 PetscCall(PetscContainerGetPointer(rB, (void **)&rb)); 72 if (rb->nonzerostate != A->nonzerostate) nonzerochange = PETSC_TRUE; 73 } 74 75 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 76 aa = av; 77 if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX || nonzerochange) { 78 /* Allocate space for symbolic transpose info and work array */ 79 PetscCall(PetscCalloc1(an + 1, &ati)); 80 PetscCall(PetscMalloc1(ai[am], &atj)); 81 /* Walk through aj and count ## of non-zeros in each row of A^T. */ 82 /* Note: offset by 1 for fast conversion into csr format. */ 83 for (i = 0; i < ai[am]; i++) ati[aj[i] + 1] += 1; 84 /* Form ati for csr format of A^T. */ 85 for (i = 0; i < an; i++) ati[i + 1] += ati[i]; 86 PetscCall(PetscMalloc1(ai[am], &ata)); 87 } else { 88 Mat_SeqAIJ *sub_B = (Mat_SeqAIJ *)(*B)->data; 89 ati = sub_B->i; 90 atj = sub_B->j; 91 ata = sub_B->a; 92 At = *B; 93 } 94 95 /* Copy ati into atfill so we have locations of the next free space in atj */ 96 PetscCall(PetscMalloc1(an, &atfill)); 97 PetscCall(PetscArraycpy(atfill, ati, an)); 98 99 /* Walk through A row-wise and mark nonzero entries of A^T. */ 100 for (i = 0; i < am; i++) { 101 anzj = ai[i + 1] - ai[i]; 102 for (j = 0; j < anzj; j++) { 103 atj[atfill[*aj]] = i; 104 ata[atfill[*aj]] = *aa++; 105 atfill[*aj++] += 1; 106 } 107 } 108 PetscCall(PetscFree(atfill)); 109 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 110 if (reuse == MAT_REUSE_MATRIX) PetscCall(PetscObjectStateIncrease((PetscObject)(*B))); 111 112 if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX || nonzerochange) { 113 PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), an, am, ati, atj, ata, &At)); 114 PetscCall(MatSetBlockSizes(At, PetscAbs(A->cmap->bs), PetscAbs(A->rmap->bs))); 115 PetscCall(MatSetType(At, ((PetscObject)A)->type_name)); 116 at = (Mat_SeqAIJ *)(At->data); 117 at->free_a = PETSC_TRUE; 118 at->free_ij = PETSC_TRUE; 119 at->nonew = 0; 120 at->maxnz = ati[an]; 121 } 122 123 if (reuse == MAT_INITIAL_MATRIX || (reuse == MAT_REUSE_MATRIX && !nonzerochange)) { 124 *B = At; 125 } else if (nonzerochange) { 126 PetscCall(MatHeaderMerge(*B, &At)); 127 PetscCall(MatTransposeSetPrecursor(A, *B)); 128 } else if (reuse == MAT_INPLACE_MATRIX) { 129 PetscCall(MatHeaderMerge(A, &At)); 130 } 131 PetscFunctionReturn(0); 132 } 133 134 /* 135 Get symbolic matrix structure of a submatrix of A, A[rstart:rend,:], 136 */ 137 PetscErrorCode MatGetSymbolicTransposeReduced_SeqAIJ(Mat A, PetscInt rstart, PetscInt rend, PetscInt *Ati[], PetscInt *Atj[]) { 138 PetscInt i, j, anzj; 139 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 140 PetscInt an = A->cmap->N; 141 PetscInt *ati, *atj, *atfill, *ai = a->i, *aj = a->j, am = ai[rend] - ai[rstart]; 142 143 PetscFunctionBegin; 144 PetscCall(PetscLogEventBegin(MAT_Getsymtransreduced, A, 0, 0, 0)); 145 146 /* Allocate space for symbolic transpose info and work array */ 147 PetscCall(PetscCalloc1(an + 1, &ati)); 148 PetscCall(PetscMalloc1(am + 1, &atj)); 149 150 /* Walk through aj and count ## of non-zeros in each row of A^T. */ 151 /* Note: offset by 1 for fast conversion into csr format. */ 152 for (i = ai[rstart]; i < ai[rend]; i++) ati[aj[i] + 1] += 1; 153 /* Form ati for csr format of A^T. */ 154 for (i = 0; i < an; i++) ati[i + 1] += ati[i]; 155 156 /* Copy ati into atfill so we have locations of the next free space in atj */ 157 PetscCall(PetscMalloc1(an + 1, &atfill)); 158 PetscCall(PetscArraycpy(atfill, ati, an)); 159 160 /* Walk through A row-wise and mark nonzero entries of A^T. */ 161 aj = aj + ai[rstart]; 162 for (i = rstart; i < rend; i++) { 163 anzj = ai[i + 1] - ai[i]; 164 for (j = 0; j < anzj; j++) { 165 atj[atfill[*aj]] = i - rstart; 166 atfill[*aj++] += 1; 167 } 168 } 169 PetscCall(PetscFree(atfill)); 170 *Ati = ati; 171 *Atj = atj; 172 173 PetscCall(PetscLogEventEnd(MAT_Getsymtransreduced, A, 0, 0, 0)); 174 PetscFunctionReturn(0); 175 } 176 177 /* 178 Returns the i and j arrays for a symbolic transpose, this is used internally within SeqAIJ code when the full 179 symbolic matrix (which can be obtained with MatTransposeSymbolic() is not needed. MatRestoreSymbolicTranspose_SeqAIJ() should be used to free the arrays. 180 */ 181 PetscErrorCode MatGetSymbolicTranspose_SeqAIJ(Mat A, PetscInt *Ati[], PetscInt *Atj[]) { 182 PetscFunctionBegin; 183 PetscCall(MatGetSymbolicTransposeReduced_SeqAIJ(A, 0, A->rmap->N, Ati, Atj)); 184 PetscFunctionReturn(0); 185 } 186 187 PetscErrorCode MatRestoreSymbolicTranspose_SeqAIJ(Mat A, PetscInt *ati[], PetscInt *atj[]) { 188 PetscFunctionBegin; 189 PetscCall(PetscFree(*ati)); 190 PetscCall(PetscFree(*atj)); 191 PetscFunctionReturn(0); 192 } 193