xref: /petsc/src/mat/graphops/order/amd/amd.c (revision 53673ba54f5aaba04b9d49ab22cf56c7a7461fe9)
1*8be712e4SBarry Smith #include <petscmat.h>
2*8be712e4SBarry Smith #include <petsc/private/matorderimpl.h>
3*8be712e4SBarry Smith #include <amd.h>
4*8be712e4SBarry Smith 
5*8be712e4SBarry Smith #if defined(PETSC_USE_64BIT_INDICES)
6*8be712e4SBarry Smith   #define amd_AMD_defaults amd_l_defaults
7*8be712e4SBarry Smith   /* the type casts are needed because PetscInt is long long while SuiteSparse_long is long and compilers warn even when they are identical */
8*8be712e4SBarry Smith   #define amd_AMD_order(a, b, c, d, e, f) amd_l_order((SuiteSparse_long)a, (SuiteSparse_long *)b, (SuiteSparse_long *)c, (SuiteSparse_long *)d, e, f)
9*8be712e4SBarry Smith #else
10*8be712e4SBarry Smith   #define amd_AMD_defaults amd_defaults
11*8be712e4SBarry Smith   #define amd_AMD_order    amd_order
12*8be712e4SBarry Smith #endif
13*8be712e4SBarry Smith 
14*8be712e4SBarry Smith /*
15*8be712e4SBarry Smith     MatGetOrdering_AMD - Find the Approximate Minimum Degree ordering
16*8be712e4SBarry Smith 
17*8be712e4SBarry Smith     This provides an interface to Tim Davis' AMD package (used by UMFPACK, CHOLMOD, MATLAB, etc).
18*8be712e4SBarry Smith */
MatGetOrdering_AMD(Mat mat,MatOrderingType type,IS * row,IS * col)19*8be712e4SBarry Smith PETSC_INTERN PetscErrorCode MatGetOrdering_AMD(Mat mat, MatOrderingType type, IS *row, IS *col)
20*8be712e4SBarry Smith {
21*8be712e4SBarry Smith   PetscInt        nrow, *perm;
22*8be712e4SBarry Smith   const PetscInt *ia, *ja;
23*8be712e4SBarry Smith   int             status;
24*8be712e4SBarry Smith   PetscReal       val;
25*8be712e4SBarry Smith   double          Control[AMD_CONTROL], Info[AMD_INFO];
26*8be712e4SBarry Smith   PetscBool       tval, done;
27*8be712e4SBarry Smith 
28*8be712e4SBarry Smith   PetscFunctionBegin;
29*8be712e4SBarry Smith   /*
30*8be712e4SBarry Smith      AMD does not require that the matrix be symmetric (it does so internally,
31*8be712e4SBarry Smith      at least in so far as computing orderings for A+A^T.
32*8be712e4SBarry Smith   */
33*8be712e4SBarry Smith   PetscCall(MatGetRowIJ(mat, 0, PETSC_FALSE, PETSC_TRUE, &nrow, &ia, &ja, &done));
34*8be712e4SBarry Smith   PetscCheck(done, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get rows for matrix type %s", ((PetscObject)mat)->type_name);
35*8be712e4SBarry Smith 
36*8be712e4SBarry Smith   amd_AMD_defaults(Control);
37*8be712e4SBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)mat), ((PetscObject)mat)->prefix, "AMD Options", "Mat");
38*8be712e4SBarry Smith   /*
39*8be712e4SBarry Smith     We have to use temporary values here because AMD always uses double, even though PetscReal may be single
40*8be712e4SBarry Smith   */
41*8be712e4SBarry Smith   val = (PetscReal)Control[AMD_DENSE];
42*8be712e4SBarry Smith   PetscCall(PetscOptionsReal("-mat_ordering_amd_dense", "threshold for \"dense\" rows/columns", "None", val, &val, NULL));
43*8be712e4SBarry Smith   Control[AMD_DENSE] = (double)val;
44*8be712e4SBarry Smith 
45*8be712e4SBarry Smith   tval = (PetscBool)Control[AMD_AGGRESSIVE];
46*8be712e4SBarry Smith   PetscCall(PetscOptionsBool("-mat_ordering_amd_aggressive", "use aggressive absorption", "None", tval, &tval, NULL));
47*8be712e4SBarry Smith   Control[AMD_AGGRESSIVE] = (double)tval;
48*8be712e4SBarry Smith 
49*8be712e4SBarry Smith   PetscOptionsEnd();
50*8be712e4SBarry Smith 
51*8be712e4SBarry Smith   PetscCall(PetscMalloc1(nrow, &perm));
52*8be712e4SBarry Smith   status = amd_AMD_order(nrow, ia, ja, perm, Control, Info);
53*8be712e4SBarry Smith   switch (status) {
54*8be712e4SBarry Smith   case AMD_OK:
55*8be712e4SBarry Smith     break;
56*8be712e4SBarry Smith   case AMD_OK_BUT_JUMBLED:
57*8be712e4SBarry Smith     /* The result is fine, but PETSc matrices are supposed to satisfy stricter preconditions, so PETSc considers a
58*8be712e4SBarry Smith     * matrix that triggers this error condition to be invalid.
59*8be712e4SBarry Smith     */
60*8be712e4SBarry Smith     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "According to AMD, the matrix has unsorted and/or duplicate row indices");
61*8be712e4SBarry Smith   case AMD_INVALID:
62*8be712e4SBarry Smith     amd_info(Info);
63*8be712e4SBarry Smith     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "According to AMD, the matrix is invalid");
64*8be712e4SBarry Smith   case AMD_OUT_OF_MEMORY:
65*8be712e4SBarry Smith     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_MEM, "AMD could not compute ordering");
66*8be712e4SBarry Smith   default:
67*8be712e4SBarry Smith     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_LIB, "Unexpected return value");
68*8be712e4SBarry Smith   }
69*8be712e4SBarry Smith   PetscCall(MatRestoreRowIJ(mat, 0, PETSC_FALSE, PETSC_TRUE, NULL, &ia, &ja, &done));
70*8be712e4SBarry Smith 
71*8be712e4SBarry Smith   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nrow, perm, PETSC_COPY_VALUES, row));
72*8be712e4SBarry Smith   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nrow, perm, PETSC_OWN_POINTER, col));
73*8be712e4SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
74*8be712e4SBarry Smith }
75