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