#include <../src/mat/impls/adj/mpi/mpiadj.h> /*I "petscmat.h" I*/ #if defined(PETSC_HAVE_UNISTD_H) #include #endif EXTERN_C_BEGIN #include EXTERN_C_END typedef struct { PetscBool redm; PetscBool redo; PetscBool recursive; PetscBool verbose; char global[15]; /* global method */ char local[15]; /* local method */ PetscInt nbvtxcoarsed; /* number of vertices for the coarse graph */ } MatPartitioning_Party; #define SIZE_LOG 10000 /* size of buffer for mesg_log */ static PetscErrorCode MatPartitioningApply_Party(MatPartitioning part, IS *partitioning) { int perr; PetscInt i, *parttab, *locals, nb_locals, M, N; PetscMPIInt size, rank; Mat mat = part->adj, matAdj, matSeq, *A; Mat_MPIAdj *adj; MatPartitioning_Party *party = (MatPartitioning_Party *)part->data; PetscBool flg; IS isrow, iscol; int n, *edge_p, *edge, *vertex_w, p, *part_party, cutsize, redl, rec; const char *redm, *redo; char *mesg_log; #if defined(PETSC_HAVE_UNISTD_H) int fd_stdout, fd_pipe[2], count; #endif PetscFunctionBegin; PetscCheck(!part->use_edge_weights, PetscObjectComm((PetscObject)part), PETSC_ERR_SUP, "Party does not support edge weights"); PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size)); PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mat), &rank)); PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATMPIADJ, &flg)); if (size > 1) { if (flg) { PetscCall(MatMPIAdjToSeq(mat, &matSeq)); } else { PetscCall(PetscInfo(part, "Converting distributed matrix to sequential: this could be a performance loss\n")); PetscCall(MatGetSize(mat, &M, &N)); PetscCall(ISCreateStride(PETSC_COMM_SELF, M, 0, 1, &isrow)); PetscCall(ISCreateStride(PETSC_COMM_SELF, N, 0, 1, &iscol)); PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscol, MAT_INITIAL_MATRIX, &A)); PetscCall(ISDestroy(&isrow)); PetscCall(ISDestroy(&iscol)); matSeq = *A; PetscCall(PetscFree(A)); } } else { PetscCall(PetscObjectReference((PetscObject)mat)); matSeq = mat; } if (!flg) { /* convert regular matrix to MPIADJ */ PetscCall(MatConvert(matSeq, MATMPIADJ, MAT_INITIAL_MATRIX, &matAdj)); } else { PetscCall(PetscObjectReference((PetscObject)matSeq)); matAdj = matSeq; } adj = (Mat_MPIAdj *)matAdj->data; /* finally adj contains adjacency graph */ /* arguments for Party library */ n = mat->rmap->N; /* number of vertices in full graph */ edge_p = adj->i; /* start of edge list for each vertex */ edge = adj->j; /* edge list data */ vertex_w = part->vertex_weights; /* weights for all vertices */ p = part->n; /* number of parts to create */ redl = party->nbvtxcoarsed; /* how many vertices to coarsen down to? */ rec = party->recursive ? 1 : 0; /* recursive bisection */ redm = party->redm ? "lam" : ""; /* matching method */ redo = party->redo ? "w3" : ""; /* matching optimization method */ PetscCall(PetscMalloc1(mat->rmap->N, &part_party)); /* redirect output to buffer */ #if defined(PETSC_HAVE_UNISTD_H) fd_stdout = dup(1); PetscCheck(!pipe(fd_pipe), PETSC_COMM_SELF, PETSC_ERR_SYS, "Could not open pipe"); close(1); dup2(fd_pipe[1], 1); PetscCall(PetscMalloc1(SIZE_LOG, &mesg_log)); #endif /* library call */ party_lib_times_start(); perr = party_lib(n, vertex_w, NULL, NULL, NULL, edge_p, edge, NULL, p, part_party, &cutsize, redl, (char *)redm, (char *)redo, party->global, party->local, rec, 1); party_lib_times_output(1); part_info(n, vertex_w, edge_p, edge, NULL, p, part_party, 1); #if defined(PETSC_HAVE_UNISTD_H) PetscCall(PetscFFlush(stdout)); count = read(fd_pipe[0], mesg_log, (SIZE_LOG - 1) * sizeof(char)); if (count < 0) count = 0; mesg_log[count] = 0; close(1); dup2(fd_stdout, 1); close(fd_stdout); close(fd_pipe[0]); close(fd_pipe[1]); if (party->verbose) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "%s", mesg_log)); PetscCall(PetscFree(mesg_log)); #endif PetscCheck(!perr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Party failed"); PetscCall(PetscMalloc1(mat->rmap->N, &parttab)); for (i = 0; i < mat->rmap->N; i++) parttab[i] = part_party[i]; /* creation of the index set */ nb_locals = mat->rmap->n; locals = parttab + mat->rmap->rstart; PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)part), nb_locals, locals, PETSC_COPY_VALUES, partitioning)); /* clean up */ PetscCall(PetscFree(parttab)); PetscCall(PetscFree(part_party)); PetscCall(MatDestroy(&matSeq)); PetscCall(MatDestroy(&matAdj)); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode MatPartitioningView_Party(MatPartitioning part, PetscViewer viewer) { MatPartitioning_Party *party = (MatPartitioning_Party *)part->data; PetscBool isascii; PetscFunctionBegin; PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); if (isascii) { PetscCall(PetscViewerASCIIPrintf(viewer, " Global method: %s\n", party->global)); PetscCall(PetscViewerASCIIPrintf(viewer, " Local method: %s\n", party->local)); PetscCall(PetscViewerASCIIPrintf(viewer, " Number of vertices for the coarse graph: %d\n", party->nbvtxcoarsed)); if (party->redm) PetscCall(PetscViewerASCIIPrintf(viewer, " Using matching method for graph reduction\n")); if (party->redo) PetscCall(PetscViewerASCIIPrintf(viewer, " Using matching optimization\n")); if (party->recursive) PetscCall(PetscViewerASCIIPrintf(viewer, " Using recursive bipartitioning\n")); } PetscFunctionReturn(PETSC_SUCCESS); } /*@ MatPartitioningPartySetGlobal - Set global method for Party partitioner. Collective Input Parameters: + part - the partitioning context - global - a string representing the method Options Database Key: . -mat_partitioning_party_global - the global method Level: advanced Note: The method may be one of `MP_PARTY_OPT`, `MP_PARTY_LIN`, `MP_PARTY_SCA`, `MP_PARTY_RAN`, `MP_PARTY_GBF`, `MP_PARTY_GCF`, `MP_PARTY_BUB` or `MP_PARTY_DEF`, or alternatively a string describing the method. Two or more methods can be combined like "gbf,gcf". Check the Party Library Users Manual for details. Developer Note: Should be `MatPartitioningPartySetGlobalType()` and all uses of method should be changed to type .seealso: `MATPARTITIONINGPARTY`, `MatPartitioningPartySetLocal()` @*/ PetscErrorCode MatPartitioningPartySetGlobal(MatPartitioning part, const char *global) { PetscFunctionBegin; PetscValidHeaderSpecific(part, MAT_PARTITIONING_CLASSID, 1); PetscTryMethod(part, "MatPartitioningPartySetGlobal_C", (MatPartitioning, const char *), (part, global)); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode MatPartitioningPartySetGlobal_Party(MatPartitioning part, const char *global) { MatPartitioning_Party *party = (MatPartitioning_Party *)part->data; PetscFunctionBegin; PetscCall(PetscStrncpy(party->global, global, 15)); PetscFunctionReturn(PETSC_SUCCESS); } /*@ MatPartitioningPartySetLocal - Set local method used by the Party partitioner. Collective Input Parameters: + part - the partitioning context - local - a string representing the method Options Database Key: . -mat_partitioning_party_local - the local method Level: advanced Note: The method may be one of `MP_PARTY_HELPFUL_SETS`, `MP_PARTY_KERNIGHAN_LIN`, or `MP_PARTY_NONE`. Check the Party Library Users Manual for details. Developer Note: Should be `MatPartitioningPartySetLocalType()` and all uses of method should be changed to type .seealso: `MATPARTITIONINGPARTY`, `MatPartitioningPartySetGlobal()` @*/ PetscErrorCode MatPartitioningPartySetLocal(MatPartitioning part, const char *local) { PetscFunctionBegin; PetscValidHeaderSpecific(part, MAT_PARTITIONING_CLASSID, 1); PetscTryMethod(part, "MatPartitioningPartySetLocal_C", (MatPartitioning, const char *), (part, local)); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode MatPartitioningPartySetLocal_Party(MatPartitioning part, const char *local) { MatPartitioning_Party *party = (MatPartitioning_Party *)part->data; PetscFunctionBegin; PetscCall(PetscStrncpy(party->local, local, 15)); PetscFunctionReturn(PETSC_SUCCESS); } /*@ MatPartitioningPartySetCoarseLevel - Set the coarse level parameter for the Party partitioner. Collective Input Parameters: + part - the partitioning context - level - the coarse level in range [0.0,1.0] Options Database Key: . -mat_partitioning_party_coarse - Coarse level Level: advanced .seealso: `MATPARTITIONINGPARTY` @*/ PetscErrorCode MatPartitioningPartySetCoarseLevel(MatPartitioning part, PetscReal level) { PetscFunctionBegin; PetscValidHeaderSpecific(part, MAT_PARTITIONING_CLASSID, 1); PetscValidLogicalCollectiveReal(part, level, 2); PetscTryMethod(part, "MatPartitioningPartySetCoarseLevel_C", (MatPartitioning, PetscReal), (part, level)); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode MatPartitioningPartySetCoarseLevel_Party(MatPartitioning part, PetscReal level) { MatPartitioning_Party *party = (MatPartitioning_Party *)part->data; PetscFunctionBegin; PetscCheck(level >= 0.0 && level <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Party: level of coarsening out of range [0.0-1.0]"); party->nbvtxcoarsed = (PetscInt)(part->adj->cmap->N * level); if (party->nbvtxcoarsed < 20) party->nbvtxcoarsed = 20; PetscFunctionReturn(PETSC_SUCCESS); } /*@ MatPartitioningPartySetMatchOptimization - Activate matching optimization for graph reduction. Collective Input Parameters: + part - the partitioning context - opt - boolean flag Options Database Key: . -mat_partitioning_party_match_optimization - Matching optimization on/off Level: advanced .seealso: `MATPARTITIONINGPARTY` @*/ PetscErrorCode MatPartitioningPartySetMatchOptimization(MatPartitioning part, PetscBool opt) { PetscFunctionBegin; PetscValidHeaderSpecific(part, MAT_PARTITIONING_CLASSID, 1); PetscValidLogicalCollectiveBool(part, opt, 2); PetscTryMethod(part, "MatPartitioningPartySetMatchOptimization_C", (MatPartitioning, PetscBool), (part, opt)); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode MatPartitioningPartySetMatchOptimization_Party(MatPartitioning part, PetscBool opt) { MatPartitioning_Party *party = (MatPartitioning_Party *)part->data; PetscFunctionBegin; party->redo = opt; PetscFunctionReturn(PETSC_SUCCESS); } /*@ MatPartitioningPartySetBipart - Activate or deactivate recursive bisection in the Party partitioner Collective Input Parameters: + part - the partitioning context - bp - boolean flag Options Database Key: . -mat_partitioning_party_bipart - Bipartitioning option on/off Level: advanced .seealso: `MATPARTITIONINGPARTY` @*/ PetscErrorCode MatPartitioningPartySetBipart(MatPartitioning part, PetscBool bp) { PetscFunctionBegin; PetscValidHeaderSpecific(part, MAT_PARTITIONING_CLASSID, 1); PetscValidLogicalCollectiveBool(part, bp, 2); PetscTryMethod(part, "MatPartitioningPartySetBipart_C", (MatPartitioning, PetscBool), (part, bp)); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode MatPartitioningPartySetBipart_Party(MatPartitioning part, PetscBool bp) { MatPartitioning_Party *party = (MatPartitioning_Party *)part->data; PetscFunctionBegin; party->recursive = bp; PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode MatPartitioningSetFromOptions_Party(MatPartitioning part, PetscOptionItems PetscOptionsObject) { PetscBool flag; char value[256]; PetscReal r; MatPartitioning_Party *party = (MatPartitioning_Party *)part->data; PetscFunctionBegin; PetscOptionsHeadBegin(PetscOptionsObject, "Set Party partitioning options"); PetscCall(PetscOptionsString("-mat_partitioning_party_global", "Global method", "MatPartitioningPartySetGlobal", party->global, value, sizeof(value), &flag)); if (flag) PetscCall(MatPartitioningPartySetGlobal(part, value)); PetscCall(PetscOptionsString("-mat_partitioning_party_local", "Local method", "MatPartitioningPartySetLocal", party->local, value, sizeof(value), &flag)); if (flag) PetscCall(MatPartitioningPartySetLocal(part, value)); PetscCall(PetscOptionsReal("-mat_partitioning_party_coarse", "Coarse level", "MatPartitioningPartySetCoarseLevel", 0.0, &r, &flag)); if (flag) PetscCall(MatPartitioningPartySetCoarseLevel(part, r)); PetscCall(PetscOptionsBool("-mat_partitioning_party_match_optimization", "Matching optimization on/off", "MatPartitioningPartySetMatchOptimization", party->redo, &party->redo, NULL)); PetscCall(PetscOptionsBool("-mat_partitioning_party_bipart", "Bipartitioning on/off", "MatPartitioningPartySetBipart", party->recursive, &party->recursive, NULL)); PetscCall(PetscOptionsBool("-mat_partitioning_party_verbose", "Show library output", "", party->verbose, &party->verbose, NULL)); PetscOptionsHeadEnd(); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode MatPartitioningDestroy_Party(MatPartitioning part) { MatPartitioning_Party *party = (MatPartitioning_Party *)part->data; PetscFunctionBegin; PetscCall(PetscFree(party)); /* clear composed functions */ PetscCall(PetscObjectComposeFunction((PetscObject)part, "MatPartitioningPartySetGlobal_C", NULL)); PetscCall(PetscObjectComposeFunction((PetscObject)part, "MatPartitioningPartySetLocal_C", NULL)); PetscCall(PetscObjectComposeFunction((PetscObject)part, "MatPartitioningPartySetCoarseLevel_C", NULL)); PetscCall(PetscObjectComposeFunction((PetscObject)part, "MatPartitioningPartySetMatchOptimization_C", NULL)); PetscCall(PetscObjectComposeFunction((PetscObject)part, "MatPartitioningPartySetBipart_C", NULL)); PetscFunctionReturn(PETSC_SUCCESS); } /*MC MATPARTITIONINGPARTY - Creates a partitioning context via the external package Party < http://wwwcs.upb.de/fachbereich/AG/monien/RESEARCH/PART/party.htm>. Level: beginner Note: Does not support the `MatPartitioningSetUseEdgeWeights()` option .seealso: `MatPartitioningSetType()`, `MatPartitioningType`, `MatPartitioningPartySetGlobal()`, `MatPartitioningPartySetLocal()`, `MatPartitioningPartySetCoarseLevel()`, `MatPartitioningPartySetMatchOptimization()`, `MatPartitioningPartySetBipart()` M*/ PETSC_EXTERN PetscErrorCode MatPartitioningCreate_Party(MatPartitioning part) { MatPartitioning_Party *party; PetscFunctionBegin; PetscCall(PetscNew(&party)); part->data = (void *)party; PetscCall(PetscStrncpy(party->global, "gcf,gbf", sizeof(party->global))); PetscCall(PetscStrncpy(party->local, "kl", sizeof(party->local))); party->redm = PETSC_TRUE; party->redo = PETSC_TRUE; party->recursive = PETSC_TRUE; party->verbose = PETSC_FALSE; party->nbvtxcoarsed = 200; part->ops->apply = MatPartitioningApply_Party; part->ops->view = MatPartitioningView_Party; part->ops->destroy = MatPartitioningDestroy_Party; part->ops->setfromoptions = MatPartitioningSetFromOptions_Party; PetscCall(PetscObjectComposeFunction((PetscObject)part, "MatPartitioningPartySetGlobal_C", MatPartitioningPartySetGlobal_Party)); PetscCall(PetscObjectComposeFunction((PetscObject)part, "MatPartitioningPartySetLocal_C", MatPartitioningPartySetLocal_Party)); PetscCall(PetscObjectComposeFunction((PetscObject)part, "MatPartitioningPartySetCoarseLevel_C", MatPartitioningPartySetCoarseLevel_Party)); PetscCall(PetscObjectComposeFunction((PetscObject)part, "MatPartitioningPartySetMatchOptimization_C", MatPartitioningPartySetMatchOptimization_Party)); PetscCall(PetscObjectComposeFunction((PetscObject)part, "MatPartitioningPartySetBipart_C", MatPartitioningPartySetBipart_Party)); PetscFunctionReturn(PETSC_SUCCESS); }