1*8be712e4SBarry Smith /* 2*8be712e4SBarry Smith Provides the code that allows PETSc users to register their own 3*8be712e4SBarry Smith sequential matrix Ordering routines. 4*8be712e4SBarry Smith */ 5*8be712e4SBarry Smith #include <petsc/private/matimpl.h> 6*8be712e4SBarry Smith #include <petscmat.h> /*I "petscmat.h" I*/ 7*8be712e4SBarry Smith 8*8be712e4SBarry Smith PetscFunctionList MatOrderingList = NULL; 9*8be712e4SBarry Smith PetscBool MatOrderingRegisterAllCalled = PETSC_FALSE; 10*8be712e4SBarry Smith 11*8be712e4SBarry Smith PETSC_INTERN PetscErrorCode MatGetOrdering_Natural(Mat mat, MatOrderingType type, IS *irow, IS *icol) 12*8be712e4SBarry Smith { 13*8be712e4SBarry Smith PetscInt n, i, *ii; 14*8be712e4SBarry Smith PetscBool done; 15*8be712e4SBarry Smith MPI_Comm comm; 16*8be712e4SBarry Smith 17*8be712e4SBarry Smith PetscFunctionBegin; 18*8be712e4SBarry Smith PetscCall(PetscObjectGetComm((PetscObject)mat, &comm)); 19*8be712e4SBarry Smith PetscCall(MatGetRowIJ(mat, 0, PETSC_FALSE, PETSC_TRUE, &n, NULL, NULL, &done)); 20*8be712e4SBarry Smith PetscCall(MatRestoreRowIJ(mat, 0, PETSC_FALSE, PETSC_TRUE, NULL, NULL, NULL, &done)); 21*8be712e4SBarry Smith if (done) { /* matrix may be "compressed" in symbolic factorization, due to i-nodes or block storage */ 22*8be712e4SBarry Smith /* 23*8be712e4SBarry Smith We actually create general index sets because this avoids mallocs to 24*8be712e4SBarry Smith to obtain the indices in the MatSolve() routines. 25*8be712e4SBarry Smith PetscCall(ISCreateStride(PETSC_COMM_SELF,n,0,1,irow)); 26*8be712e4SBarry Smith PetscCall(ISCreateStride(PETSC_COMM_SELF,n,0,1,icol)); 27*8be712e4SBarry Smith */ 28*8be712e4SBarry Smith PetscCall(PetscMalloc1(n, &ii)); 29*8be712e4SBarry Smith for (i = 0; i < n; i++) ii[i] = i; 30*8be712e4SBarry Smith PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n, ii, PETSC_COPY_VALUES, irow)); 31*8be712e4SBarry Smith PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n, ii, PETSC_OWN_POINTER, icol)); 32*8be712e4SBarry Smith } else { 33*8be712e4SBarry Smith PetscInt start, end; 34*8be712e4SBarry Smith 35*8be712e4SBarry Smith PetscCall(MatGetOwnershipRange(mat, &start, &end)); 36*8be712e4SBarry Smith PetscCall(ISCreateStride(comm, end - start, start, 1, irow)); 37*8be712e4SBarry Smith PetscCall(ISCreateStride(comm, end - start, start, 1, icol)); 38*8be712e4SBarry Smith } 39*8be712e4SBarry Smith PetscCall(ISSetIdentity(*irow)); 40*8be712e4SBarry Smith PetscCall(ISSetIdentity(*icol)); 41*8be712e4SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 42*8be712e4SBarry Smith } 43*8be712e4SBarry Smith 44*8be712e4SBarry Smith /* 45*8be712e4SBarry Smith Orders the rows (and columns) by the lengths of the rows. 46*8be712e4SBarry Smith This produces a symmetric Ordering but does not require a 47*8be712e4SBarry Smith matrix with symmetric non-zero structure. 48*8be712e4SBarry Smith */ 49*8be712e4SBarry Smith PETSC_INTERN PetscErrorCode MatGetOrdering_RowLength(Mat mat, MatOrderingType type, IS *irow, IS *icol) 50*8be712e4SBarry Smith { 51*8be712e4SBarry Smith PetscInt n, *permr, *lens, i; 52*8be712e4SBarry Smith const PetscInt *ia, *ja; 53*8be712e4SBarry Smith PetscBool done; 54*8be712e4SBarry Smith 55*8be712e4SBarry Smith PetscFunctionBegin; 56*8be712e4SBarry Smith PetscCall(MatGetRowIJ(mat, 0, PETSC_FALSE, PETSC_TRUE, &n, &ia, &ja, &done)); 57*8be712e4SBarry Smith PetscCheck(done, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot get rows for matrix"); 58*8be712e4SBarry Smith 59*8be712e4SBarry Smith PetscCall(PetscMalloc2(n, &lens, n, &permr)); 60*8be712e4SBarry Smith for (i = 0; i < n; i++) { 61*8be712e4SBarry Smith lens[i] = ia[i + 1] - ia[i]; 62*8be712e4SBarry Smith permr[i] = i; 63*8be712e4SBarry Smith } 64*8be712e4SBarry Smith PetscCall(MatRestoreRowIJ(mat, 0, PETSC_FALSE, PETSC_TRUE, NULL, &ia, &ja, &done)); 65*8be712e4SBarry Smith 66*8be712e4SBarry Smith PetscCall(PetscSortIntWithPermutation(n, lens, permr)); 67*8be712e4SBarry Smith 68*8be712e4SBarry Smith PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n, permr, PETSC_COPY_VALUES, irow)); 69*8be712e4SBarry Smith PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n, permr, PETSC_COPY_VALUES, icol)); 70*8be712e4SBarry Smith PetscCall(PetscFree2(lens, permr)); 71*8be712e4SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 72*8be712e4SBarry Smith } 73*8be712e4SBarry Smith 74*8be712e4SBarry Smith /*@C 75*8be712e4SBarry Smith MatOrderingRegister - Adds a new sparse matrix ordering to the matrix package. 76*8be712e4SBarry Smith 77*8be712e4SBarry Smith Not Collective 78*8be712e4SBarry Smith 79*8be712e4SBarry Smith Input Parameters: 80*8be712e4SBarry Smith + sname - name of ordering (for example `MATORDERINGND`) 81*8be712e4SBarry Smith - function - function pointer that creates the ordering 82*8be712e4SBarry Smith 83*8be712e4SBarry Smith Level: developer 84*8be712e4SBarry Smith 85*8be712e4SBarry Smith Example Usage: 86*8be712e4SBarry Smith .vb 87*8be712e4SBarry Smith MatOrderingRegister("my_order", MyOrder); 88*8be712e4SBarry Smith .ve 89*8be712e4SBarry Smith 90*8be712e4SBarry Smith Then, your partitioner can be chosen with the procedural interface via 91*8be712e4SBarry Smith $ MatOrderingSetType(part, "my_order) 92*8be712e4SBarry Smith or at runtime via the option 93*8be712e4SBarry Smith $ -pc_factor_mat_ordering_type my_order 94*8be712e4SBarry Smith 95*8be712e4SBarry Smith .seealso: `MatOrderingRegisterAll()`, `MatGetOrdering()` 96*8be712e4SBarry Smith @*/ 97*8be712e4SBarry Smith PetscErrorCode MatOrderingRegister(const char sname[], PetscErrorCode (*function)(Mat, MatOrderingType, IS *, IS *)) 98*8be712e4SBarry Smith { 99*8be712e4SBarry Smith PetscFunctionBegin; 100*8be712e4SBarry Smith PetscCall(MatInitializePackage()); 101*8be712e4SBarry Smith PetscCall(PetscFunctionListAdd(&MatOrderingList, sname, function)); 102*8be712e4SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 103*8be712e4SBarry Smith } 104*8be712e4SBarry Smith 105*8be712e4SBarry Smith #include <../src/mat/impls/aij/mpi/mpiaij.h> 106*8be712e4SBarry Smith /*@C 107*8be712e4SBarry Smith MatGetOrdering - Gets a reordering for a matrix to reduce fill or to 108*8be712e4SBarry Smith improve numerical stability of LU factorization. 109*8be712e4SBarry Smith 110*8be712e4SBarry Smith Collective 111*8be712e4SBarry Smith 112*8be712e4SBarry Smith Input Parameters: 113*8be712e4SBarry Smith + mat - the matrix 114*8be712e4SBarry Smith - type - type of reordering, one of the following 115*8be712e4SBarry Smith .vb 116*8be712e4SBarry Smith MATORDERINGNATURAL_OR_ND - Nested dissection unless matrix is SBAIJ then it is natural 117*8be712e4SBarry Smith MATORDERINGNATURAL - Natural 118*8be712e4SBarry Smith MATORDERINGND - Nested Dissection 119*8be712e4SBarry Smith MATORDERING1WD - One-way Dissection 120*8be712e4SBarry Smith MATORDERINGRCM - Reverse Cuthill-McKee 121*8be712e4SBarry Smith MATORDERINGQMD - Quotient Minimum Degree 122*8be712e4SBarry Smith MATORDERINGEXTERNAL - Use an ordering internal to the factorzation package and do not compute or use PETSc's 123*8be712e4SBarry Smith .ve 124*8be712e4SBarry Smith 125*8be712e4SBarry Smith Output Parameters: 126*8be712e4SBarry Smith + rperm - row permutation indices 127*8be712e4SBarry Smith - cperm - column permutation indices 128*8be712e4SBarry Smith 129*8be712e4SBarry Smith Options Database Key: 130*8be712e4SBarry Smith + -mat_view_ordering draw - plots matrix nonzero structure in new ordering 131*8be712e4SBarry Smith - -pc_factor_mat_ordering_type <nd,natural,..> - ordering to use with `PC`s based on factorization, `MATLU`, `MATILU`, MATCHOLESKY`, `MATICC` 132*8be712e4SBarry Smith 133*8be712e4SBarry Smith Level: intermediate 134*8be712e4SBarry Smith 135*8be712e4SBarry Smith Notes: 136*8be712e4SBarry Smith This DOES NOT actually reorder the matrix; it merely returns two index sets 137*8be712e4SBarry Smith that define a reordering. This is usually not used directly, rather use the 138*8be712e4SBarry Smith options `PCFactorSetMatOrderingType()` 139*8be712e4SBarry Smith 140*8be712e4SBarry Smith The user can define additional orderings; see `MatOrderingRegister()`. 141*8be712e4SBarry Smith 142*8be712e4SBarry Smith These are generally only implemented for sequential sparse matrices. 143*8be712e4SBarry Smith 144*8be712e4SBarry Smith Some external packages that PETSc can use for direct factorization such as SuperLU_DIST do not accept orderings provided by 145*8be712e4SBarry Smith this call. 146*8be712e4SBarry Smith 147*8be712e4SBarry Smith If `MATORDERINGEXTERNAL` is used then PETSc does not compute an ordering and utilizes one built into the factorization package 148*8be712e4SBarry Smith 149*8be712e4SBarry Smith .seealso: `MatOrderingRegister()`, `PCFactorSetMatOrderingType()`, `MatColoring`, `MatColoringCreate()`, `MatOrderingType`, `Mat` 150*8be712e4SBarry Smith @*/ 151*8be712e4SBarry Smith PetscErrorCode MatGetOrdering(Mat mat, MatOrderingType type, IS *rperm, IS *cperm) 152*8be712e4SBarry Smith { 153*8be712e4SBarry Smith PetscInt mmat, nmat, mis; 154*8be712e4SBarry Smith PetscErrorCode (*r)(Mat, MatOrderingType, IS *, IS *); 155*8be712e4SBarry Smith PetscBool flg, ismpiaij; 156*8be712e4SBarry Smith 157*8be712e4SBarry Smith PetscFunctionBegin; 158*8be712e4SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 159*8be712e4SBarry Smith PetscAssertPointer(rperm, 3); 160*8be712e4SBarry Smith PetscAssertPointer(cperm, 4); 161*8be712e4SBarry Smith PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 162*8be712e4SBarry Smith PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 163*8be712e4SBarry Smith PetscCheck(type, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Ordering type cannot be null"); 164*8be712e4SBarry Smith 165*8be712e4SBarry Smith PetscCall(PetscStrcmp(type, MATORDERINGEXTERNAL, &flg)); 166*8be712e4SBarry Smith if (flg) { 167*8be712e4SBarry Smith *rperm = NULL; 168*8be712e4SBarry Smith *cperm = NULL; 169*8be712e4SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 170*8be712e4SBarry Smith } 171*8be712e4SBarry Smith 172*8be712e4SBarry Smith /* This code is terrible. MatGetOrdering() multiple dispatch should use matrix and this code should move to impls/aij/mpi. */ 173*8be712e4SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATMPIAIJ, &ismpiaij)); 174*8be712e4SBarry Smith if (ismpiaij) { /* Reorder using diagonal block */ 175*8be712e4SBarry Smith Mat Ad, Ao; 176*8be712e4SBarry Smith const PetscInt *colmap; 177*8be712e4SBarry Smith IS lrowperm, lcolperm; 178*8be712e4SBarry Smith PetscInt i, rstart, rend, *idx; 179*8be712e4SBarry Smith const PetscInt *lidx; 180*8be712e4SBarry Smith 181*8be712e4SBarry Smith PetscCall(MatMPIAIJGetSeqAIJ(mat, &Ad, &Ao, &colmap)); 182*8be712e4SBarry Smith PetscCall(MatGetOrdering(Ad, type, &lrowperm, &lcolperm)); 183*8be712e4SBarry Smith PetscCall(MatGetOwnershipRange(mat, &rstart, &rend)); 184*8be712e4SBarry Smith /* Remap row index set to global space */ 185*8be712e4SBarry Smith PetscCall(ISGetIndices(lrowperm, &lidx)); 186*8be712e4SBarry Smith PetscCall(PetscMalloc1(rend - rstart, &idx)); 187*8be712e4SBarry Smith for (i = 0; i + rstart < rend; i++) idx[i] = rstart + lidx[i]; 188*8be712e4SBarry Smith PetscCall(ISRestoreIndices(lrowperm, &lidx)); 189*8be712e4SBarry Smith PetscCall(ISDestroy(&lrowperm)); 190*8be712e4SBarry Smith PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), rend - rstart, idx, PETSC_OWN_POINTER, rperm)); 191*8be712e4SBarry Smith PetscCall(ISSetPermutation(*rperm)); 192*8be712e4SBarry Smith /* Remap column index set to global space */ 193*8be712e4SBarry Smith PetscCall(ISGetIndices(lcolperm, &lidx)); 194*8be712e4SBarry Smith PetscCall(PetscMalloc1(rend - rstart, &idx)); 195*8be712e4SBarry Smith for (i = 0; i + rstart < rend; i++) idx[i] = rstart + lidx[i]; 196*8be712e4SBarry Smith PetscCall(ISRestoreIndices(lcolperm, &lidx)); 197*8be712e4SBarry Smith PetscCall(ISDestroy(&lcolperm)); 198*8be712e4SBarry Smith PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), rend - rstart, idx, PETSC_OWN_POINTER, cperm)); 199*8be712e4SBarry Smith PetscCall(ISSetPermutation(*cperm)); 200*8be712e4SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 201*8be712e4SBarry Smith } 202*8be712e4SBarry Smith 203*8be712e4SBarry Smith if (!mat->rmap->N) { /* matrix has zero rows */ 204*8be712e4SBarry Smith PetscCall(ISCreateStride(PETSC_COMM_SELF, 0, 0, 1, cperm)); 205*8be712e4SBarry Smith PetscCall(ISCreateStride(PETSC_COMM_SELF, 0, 0, 1, rperm)); 206*8be712e4SBarry Smith PetscCall(ISSetIdentity(*cperm)); 207*8be712e4SBarry Smith PetscCall(ISSetIdentity(*rperm)); 208*8be712e4SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 209*8be712e4SBarry Smith } 210*8be712e4SBarry Smith 211*8be712e4SBarry Smith PetscCall(MatGetLocalSize(mat, &mmat, &nmat)); 212*8be712e4SBarry Smith PetscCheck(mmat == nmat, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must be square matrix, rows %" PetscInt_FMT " columns %" PetscInt_FMT, mmat, nmat); 213*8be712e4SBarry Smith 214*8be712e4SBarry Smith PetscCall(MatOrderingRegisterAll()); 215*8be712e4SBarry Smith PetscCall(PetscFunctionListFind(MatOrderingList, type, &r)); 216*8be712e4SBarry Smith PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown or unregistered type: %s", type); 217*8be712e4SBarry Smith 218*8be712e4SBarry Smith PetscCall(PetscLogEventBegin(MAT_GetOrdering, mat, 0, 0, 0)); 219*8be712e4SBarry Smith PetscCall((*r)(mat, type, rperm, cperm)); 220*8be712e4SBarry Smith PetscCall(ISSetPermutation(*rperm)); 221*8be712e4SBarry Smith PetscCall(ISSetPermutation(*cperm)); 222*8be712e4SBarry Smith /* Adjust for inode (reduced matrix ordering) only if row permutation is smaller the matrix size */ 223*8be712e4SBarry Smith PetscCall(ISGetLocalSize(*rperm, &mis)); 224*8be712e4SBarry Smith if (mmat > mis) PetscCall(MatInodeAdjustForInodes(mat, rperm, cperm)); 225*8be712e4SBarry Smith PetscCall(PetscLogEventEnd(MAT_GetOrdering, mat, 0, 0, 0)); 226*8be712e4SBarry Smith 227*8be712e4SBarry Smith PetscCall(PetscOptionsHasName(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-mat_view_ordering", &flg)); 228*8be712e4SBarry Smith if (flg) { 229*8be712e4SBarry Smith Mat tmat; 230*8be712e4SBarry Smith PetscCall(MatPermute(mat, *rperm, *cperm, &tmat)); 231*8be712e4SBarry Smith PetscCall(MatViewFromOptions(tmat, (PetscObject)mat, "-mat_view_ordering")); 232*8be712e4SBarry Smith PetscCall(MatDestroy(&tmat)); 233*8be712e4SBarry Smith } 234*8be712e4SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 235*8be712e4SBarry Smith } 236*8be712e4SBarry Smith 237*8be712e4SBarry Smith PetscErrorCode MatGetOrderingList(PetscFunctionList *list) 238*8be712e4SBarry Smith { 239*8be712e4SBarry Smith PetscFunctionBegin; 240*8be712e4SBarry Smith *list = MatOrderingList; 241*8be712e4SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 242*8be712e4SBarry Smith } 243