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 */ 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