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 */ 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)); 447fb60732SBarry Smith PetscCall(MatSetBlockSizes(At, PetscAbs(A->cmap->bs), PetscAbs(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 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()"); 727fb60732SBarry Smith PetscCall(PetscContainerGetPointer(rB, (void **)&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)); 1259566063dSJacob Faibussowitsch PetscCall(MatSetBlockSizes(At, PetscAbs(A->cmap->bs), PetscAbs(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 /* 146*0b4b7b1cSBarry Smith Get symbolic matrix nonzero structure of a submatrix of A, A[rstart:rend,:], 1477fb60732SBarry Smith */ 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 */ 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 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