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