xref: /petsc/src/mat/impls/aij/seq/symtranspose.c (revision a69119a591a03a9d906b29c0a4e9802e4d7c9795)
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