170f19b1fSKris Buschelman /*
27fb60732SBarry Smith Defines transpose routines for SeqAIJ matrices.
370f19b1fSKris Buschelman */
470f19b1fSKris Buschelman
5c6db04a5SJed Brown #include <../src/mat/impls/aij/seq/aij.h>
670f19b1fSKris Buschelman
77fb60732SBarry Smith /*
87fb60732SBarry Smith The symbolic and full transpose versions share several similar code blocks but the macros to reuse the code would be confusing and ugly
97fb60732SBarry Smith */
MatTransposeSymbolic_SeqAIJ(Mat A,Mat * B)10d71ae5a4SJacob Faibussowitsch PetscErrorCode MatTransposeSymbolic_SeqAIJ(Mat A, Mat *B)
11d71ae5a4SJacob Faibussowitsch {
122e111b49SBarry Smith PetscInt i, j, anzj;
137fb60732SBarry Smith Mat At;
147fb60732SBarry Smith Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *at;
15d0f46423SBarry Smith PetscInt an = A->cmap->N, am = A->rmap->N;
162e111b49SBarry Smith PetscInt *ati, *atj, *atfill, *ai = a->i, *aj = a->j;
1770f19b1fSKris Buschelman
1870f19b1fSKris Buschelman PetscFunctionBegin;
1970f19b1fSKris Buschelman /* Allocate space for symbolic transpose info and work array */
209566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(an + 1, &ati));
219566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(ai[am], &atj));
2270f19b1fSKris Buschelman
2370f19b1fSKris Buschelman /* Walk through aj and count ## of non-zeros in each row of A^T. */
2470f19b1fSKris Buschelman /* Note: offset by 1 for fast conversion into csr format. */
257fb60732SBarry Smith for (i = 0; i < ai[am]; i++) ati[aj[i] + 1] += 1;
2670f19b1fSKris Buschelman /* Form ati for csr format of A^T. */
277fb60732SBarry Smith for (i = 0; i < an; i++) ati[i + 1] += ati[i];
2870f19b1fSKris Buschelman
2970f19b1fSKris Buschelman /* Copy ati into atfill so we have locations of the next free space in atj */
307fb60732SBarry Smith PetscCall(PetscMalloc1(an, &atfill));
319566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(atfill, ati, an));
3270f19b1fSKris Buschelman
3370f19b1fSKris Buschelman /* Walk through A row-wise and mark nonzero entries of A^T. */
3470f19b1fSKris Buschelman for (i = 0; i < am; i++) {
3570f19b1fSKris Buschelman anzj = ai[i + 1] - ai[i];
3670f19b1fSKris Buschelman for (j = 0; j < anzj; j++) {
3770f19b1fSKris Buschelman atj[atfill[*aj]] = i;
3870f19b1fSKris Buschelman atfill[*aj++] += 1;
3970f19b1fSKris Buschelman }
4070f19b1fSKris Buschelman }
419566063dSJacob Faibussowitsch PetscCall(PetscFree(atfill));
4270f19b1fSKris Buschelman
437fb60732SBarry Smith PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), an, am, ati, atj, NULL, &At));
4458b7e2c1SStefano Zampini PetscCall(MatSetBlockSizes(At, A->cmap->bs, A->rmap->bs));
457fb60732SBarry Smith PetscCall(MatSetType(At, ((PetscObject)A)->type_name));
467fb60732SBarry Smith at = (Mat_SeqAIJ *)At->data;
477fb60732SBarry Smith at->free_a = PETSC_FALSE;
487fb60732SBarry Smith at->free_ij = PETSC_TRUE;
497fb60732SBarry Smith at->nonew = 0;
507fb60732SBarry Smith at->maxnz = ati[an];
517fb60732SBarry Smith *B = At;
523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
530390132cSHong Zhang }
5470f19b1fSKris Buschelman
MatTranspose_SeqAIJ(Mat A,MatReuse reuse,Mat * B)55d71ae5a4SJacob Faibussowitsch PetscErrorCode MatTranspose_SeqAIJ(Mat A, MatReuse reuse, Mat *B)
56d71ae5a4SJacob Faibussowitsch {
572e111b49SBarry Smith PetscInt i, j, anzj;
5870f19b1fSKris Buschelman Mat At;
5970f19b1fSKris Buschelman Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *at;
60d0f46423SBarry Smith PetscInt an = A->cmap->N, am = A->rmap->N;
612e111b49SBarry Smith PetscInt *ati, *atj, *atfill, *ai = a->i, *aj = a->j;
62ce496241SStefano Zampini MatScalar *ata;
63ce496241SStefano Zampini const MatScalar *aa, *av;
647fb60732SBarry Smith PetscContainer rB;
657fb60732SBarry Smith MatParentState *rb;
667fb60732SBarry Smith PetscBool nonzerochange = PETSC_FALSE;
672e111b49SBarry Smith
6870f19b1fSKris Buschelman PetscFunctionBegin;
697fb60732SBarry Smith if (reuse == MAT_REUSE_MATRIX) {
707fb60732SBarry Smith PetscCall(PetscObjectQuery((PetscObject)*B, "MatTransposeParent", (PetscObject *)&rB));
717fb60732SBarry Smith PetscCheck(rB, PetscObjectComm((PetscObject)*B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from call to MatTranspose()");
72*2a8381b2SBarry Smith PetscCall(PetscContainerGetPointer(rB, &rb));
737fb60732SBarry Smith if (rb->nonzerostate != A->nonzerostate) nonzerochange = PETSC_TRUE;
747fb60732SBarry Smith }
757fb60732SBarry Smith
769566063dSJacob Faibussowitsch PetscCall(MatSeqAIJGetArrayRead(A, &av));
77ce496241SStefano Zampini aa = av;
787fb60732SBarry Smith if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX || nonzerochange) {
7970f19b1fSKris Buschelman /* Allocate space for symbolic transpose info and work array */
809566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(an + 1, &ati));
819566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(ai[am], &atj));
8270f19b1fSKris Buschelman /* Walk through aj and count ## of non-zeros in each row of A^T. */
8370f19b1fSKris Buschelman /* Note: offset by 1 for fast conversion into csr format. */
847fb60732SBarry Smith for (i = 0; i < ai[am]; i++) ati[aj[i] + 1] += 1;
8570f19b1fSKris Buschelman /* Form ati for csr format of A^T. */
867fb60732SBarry Smith for (i = 0; i < an; i++) ati[i + 1] += ati[i];
877fb60732SBarry Smith PetscCall(PetscMalloc1(ai[am], &ata));
887fb60732SBarry Smith } else {
89fc4dec0aSBarry Smith Mat_SeqAIJ *sub_B = (Mat_SeqAIJ *)(*B)->data;
90fc4dec0aSBarry Smith ati = sub_B->i;
91fc4dec0aSBarry Smith atj = sub_B->j;
92fc4dec0aSBarry Smith ata = sub_B->a;
93fc4dec0aSBarry Smith At = *B;
94fc4dec0aSBarry Smith }
9570f19b1fSKris Buschelman
9670f19b1fSKris Buschelman /* Copy ati into atfill so we have locations of the next free space in atj */
979566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(an, &atfill));
989566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(atfill, ati, an));
9970f19b1fSKris Buschelman
10070f19b1fSKris Buschelman /* Walk through A row-wise and mark nonzero entries of A^T. */
1017791ebe2SStefano Zampini if (aa) {
10270f19b1fSKris Buschelman for (i = 0; i < am; i++) {
10370f19b1fSKris Buschelman anzj = ai[i + 1] - ai[i];
10470f19b1fSKris Buschelman for (j = 0; j < anzj; j++) {
10570f19b1fSKris Buschelman atj[atfill[*aj]] = i;
10670f19b1fSKris Buschelman ata[atfill[*aj]] = *aa++;
10770f19b1fSKris Buschelman atfill[*aj++] += 1;
10870f19b1fSKris Buschelman }
10970f19b1fSKris Buschelman }
1107791ebe2SStefano Zampini } else {
1117791ebe2SStefano Zampini for (i = 0; i < am; i++) {
1127791ebe2SStefano Zampini anzj = ai[i + 1] - ai[i];
1137791ebe2SStefano Zampini for (j = 0; j < anzj; j++) {
1147791ebe2SStefano Zampini atj[atfill[*aj]] = i;
1157791ebe2SStefano Zampini atfill[*aj++] += 1;
1167791ebe2SStefano Zampini }
1177791ebe2SStefano Zampini }
1187791ebe2SStefano Zampini }
1199566063dSJacob Faibussowitsch PetscCall(PetscFree(atfill));
1207fb60732SBarry Smith PetscCall(MatSeqAIJRestoreArrayRead(A, &av));
121f4f49eeaSPierre Jolivet if (reuse == MAT_REUSE_MATRIX) PetscCall(PetscObjectStateIncrease((PetscObject)*B));
1227fb60732SBarry Smith
1237fb60732SBarry Smith if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX || nonzerochange) {
1249566063dSJacob Faibussowitsch PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), an, am, ati, atj, ata, &At));
12558b7e2c1SStefano Zampini PetscCall(MatSetBlockSizes(At, A->cmap->bs, A->rmap->bs));
1267fb60732SBarry Smith PetscCall(MatSetType(At, ((PetscObject)A)->type_name));
127f4f49eeaSPierre Jolivet at = (Mat_SeqAIJ *)At->data;
128e6b907acSBarry Smith at->free_a = PETSC_TRUE;
129e6b907acSBarry Smith at->free_ij = PETSC_TRUE;
13070f19b1fSKris Buschelman at->nonew = 0;
13165ac4ee0Sandi selinger at->maxnz = ati[an];
132fc4dec0aSBarry Smith }
133fc4dec0aSBarry Smith
1347fb60732SBarry Smith if (reuse == MAT_INITIAL_MATRIX || (reuse == MAT_REUSE_MATRIX && !nonzerochange)) {
13570f19b1fSKris Buschelman *B = At;
1367fb60732SBarry Smith } else if (nonzerochange) {
1377fb60732SBarry Smith PetscCall(MatHeaderMerge(*B, &At));
1387fb60732SBarry Smith PetscCall(MatTransposeSetPrecursor(A, *B));
1397fb60732SBarry Smith } else if (reuse == MAT_INPLACE_MATRIX) {
1409566063dSJacob Faibussowitsch PetscCall(MatHeaderMerge(A, &At));
14170f19b1fSKris Buschelman }
1423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
14370f19b1fSKris Buschelman }
14470f19b1fSKris Buschelman
1457fb60732SBarry Smith /*
1460b4b7b1cSBarry Smith Get symbolic matrix nonzero structure of a submatrix of A, A[rstart:rend,:],
1477fb60732SBarry Smith */
MatGetSymbolicTransposeReduced_SeqAIJ(Mat A,PetscInt rstart,PetscInt rend,PetscInt * Ati[],PetscInt * Atj[])148d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetSymbolicTransposeReduced_SeqAIJ(Mat A, PetscInt rstart, PetscInt rend, PetscInt *Ati[], PetscInt *Atj[])
149d71ae5a4SJacob Faibussowitsch {
1507fb60732SBarry Smith PetscInt i, j, anzj;
1517fb60732SBarry Smith Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
1527fb60732SBarry Smith PetscInt an = A->cmap->N;
1537fb60732SBarry Smith PetscInt *ati, *atj, *atfill, *ai = a->i, *aj = a->j, am = ai[rend] - ai[rstart];
1547fb60732SBarry Smith
1557fb60732SBarry Smith PetscFunctionBegin;
1567fb60732SBarry Smith PetscCall(PetscLogEventBegin(MAT_Getsymtransreduced, A, 0, 0, 0));
1577fb60732SBarry Smith
1587fb60732SBarry Smith /* Allocate space for symbolic transpose info and work array */
1597fb60732SBarry Smith PetscCall(PetscCalloc1(an + 1, &ati));
1607fb60732SBarry Smith PetscCall(PetscMalloc1(am + 1, &atj));
1617fb60732SBarry Smith
1627fb60732SBarry Smith /* Walk through aj and count ## of non-zeros in each row of A^T. */
1637fb60732SBarry Smith /* Note: offset by 1 for fast conversion into csr format. */
1647fb60732SBarry Smith for (i = ai[rstart]; i < ai[rend]; i++) ati[aj[i] + 1] += 1;
1657fb60732SBarry Smith /* Form ati for csr format of A^T. */
1667fb60732SBarry Smith for (i = 0; i < an; i++) ati[i + 1] += ati[i];
1677fb60732SBarry Smith
1687fb60732SBarry Smith /* Copy ati into atfill so we have locations of the next free space in atj */
1697fb60732SBarry Smith PetscCall(PetscMalloc1(an + 1, &atfill));
1707fb60732SBarry Smith PetscCall(PetscArraycpy(atfill, ati, an));
1717fb60732SBarry Smith
1727fb60732SBarry Smith /* Walk through A row-wise and mark nonzero entries of A^T. */
1738e3a54c0SPierre Jolivet aj = PetscSafePointerPlusOffset(aj, ai[rstart]);
1747fb60732SBarry Smith for (i = rstart; i < rend; i++) {
1757fb60732SBarry Smith anzj = ai[i + 1] - ai[i];
1767fb60732SBarry Smith for (j = 0; j < anzj; j++) {
1777fb60732SBarry Smith atj[atfill[*aj]] = i - rstart;
1787fb60732SBarry Smith atfill[*aj++] += 1;
1797fb60732SBarry Smith }
1807fb60732SBarry Smith }
1817fb60732SBarry Smith PetscCall(PetscFree(atfill));
1827fb60732SBarry Smith *Ati = ati;
1837fb60732SBarry Smith *Atj = atj;
1847fb60732SBarry Smith
1857fb60732SBarry Smith PetscCall(PetscLogEventEnd(MAT_Getsymtransreduced, A, 0, 0, 0));
1863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1877fb60732SBarry Smith }
1887fb60732SBarry Smith
1897fb60732SBarry Smith /*
1907fb60732SBarry Smith Returns the i and j arrays for a symbolic transpose, this is used internally within SeqAIJ code when the full
1917fb60732SBarry Smith symbolic matrix (which can be obtained with MatTransposeSymbolic() is not needed. MatRestoreSymbolicTranspose_SeqAIJ() should be used to free the arrays.
1927fb60732SBarry Smith */
MatGetSymbolicTranspose_SeqAIJ(Mat A,PetscInt * Ati[],PetscInt * Atj[])193d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetSymbolicTranspose_SeqAIJ(Mat A, PetscInt *Ati[], PetscInt *Atj[])
194d71ae5a4SJacob Faibussowitsch {
1957fb60732SBarry Smith PetscFunctionBegin;
1967fb60732SBarry Smith PetscCall(MatGetSymbolicTransposeReduced_SeqAIJ(A, 0, A->rmap->N, Ati, Atj));
1973ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1987fb60732SBarry Smith }
1997fb60732SBarry Smith
MatRestoreSymbolicTranspose_SeqAIJ(Mat A,PetscInt * ati[],PetscInt * atj[])200d71ae5a4SJacob Faibussowitsch PetscErrorCode MatRestoreSymbolicTranspose_SeqAIJ(Mat A, PetscInt *ati[], PetscInt *atj[])
201d71ae5a4SJacob Faibussowitsch {
20270f19b1fSKris Buschelman PetscFunctionBegin;
2039566063dSJacob Faibussowitsch PetscCall(PetscFree(*ati));
2049566063dSJacob Faibussowitsch PetscCall(PetscFree(*atj));
2053ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
20670f19b1fSKris Buschelman }
207