void MlevelNestedDissectionCC(ctrl_t *ctrl, graph_t *graph, idx_t *order, idx_t lastvtx) { idx_t i, j, nvtxs, nbnd, ncmps, rnvtxs, snvtxs; idx_t *label, *bndind; idx_t *cptr, *cind; graph_t **sgraphs; nvtxs = graph->nvtxs; MlevelNodeBisectionMultiple(ctrl, graph); IFSET(ctrl->dbglvl, METIS_DBG_SEPINFO, printf("Nvtxs: %6"PRIDX", [%6"PRIDX" %6"PRIDX" %6"PRIDX"]\n", graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2])); /* Order the nodes in the separator */ nbnd = graph->nbnd; bndind = graph->bndind; label = graph->label; for (i=0; i<nbnd; i++) order[label[bndind[i]]] = --lastvtx; WCOREPUSH; cptr = iwspacemalloc(ctrl, nvtxs+1); cind = iwspacemalloc(ctrl, nvtxs); ncmps = FindSepInducedComponents(ctrl, graph, cptr, cind); if (ctrl->dbglvl&METIS_DBG_INFO) { if (ncmps > 2) printf(" Bisection resulted in %"PRIDX" connected components\n", ncmps); } sgraphs = SplitGraphOrderCC(ctrl, graph, ncmps, cptr, cind); WCOREPOP; /* Free the memory of the top level graph */ FreeGraph(&graph); /* Go and process the subgraphs */ for (rnvtxs=i=0; i<ncmps; i++) { /* Save the number of vertices in sgraphs[i] because sgraphs[i] is freed inside MlevelNestedDissectionCC, and as such it will be undefined. */ snvtxs = sgraphs[i]->nvtxs; if (sgraphs[i]->nvtxs > MMDSWITCH && sgraphs[i]->nedges > 0) { MlevelNestedDissectionCC(ctrl, sgraphs[i], order, lastvtx-rnvtxs); } else { MMDOrder(ctrl, sgraphs[i], order, lastvtx-rnvtxs); FreeGraph(&sgraphs[i]); } rnvtxs += snvtxs; } gk_free((void **)&sgraphs, LTERM); }
int main(int argc, char *argv[]) { graph_t *graph, *fgraph; char filename[256]; idx_t wgtflag; params_t params; if (argc != 2 && argc != 3) { printf("Usage: %s <GraphFile> [FixedGraphFile (for storing the fixed graph)]\n", argv[0]); exit(0); } memset((void *) ¶ms, 0, sizeof(params_t)); params.filename = gk_strdup(argv[1]); graph = ReadGraph(¶ms); if (graph->nvtxs == 0) { printf("Empty graph!\n"); exit(0); } printf("**********************************************************************\n"); printf("%s", METISTITLE); printf(" (HEAD: %s, Built on: %s, %s)\n", SVNINFO, __DATE__, __TIME__); printf(" size of idx_t: %zubits, real_t: %zubits, idx_t *: %zubits\n", 8 * sizeof(idx_t), 8 * sizeof(real_t), 8 * sizeof(idx_t * )); printf("\n"); printf("Graph Information ---------------------------------------------------\n"); printf(" Name: %s, #Vertices: %"PRIDX", #Edges: %"PRIDX"\n\n", params.filename, graph->nvtxs, graph->nedges / 2); printf("Checking Graph... ---------------------------------------------------\n"); if (CheckGraph(graph, 1, 1)) { printf(" The format of the graph is correct!\n"); } else { printf(" The format of the graph is incorrect!\n"); if (argc == 3) { fgraph = FixGraph(graph); WriteGraph(fgraph, argv[2]); FreeGraph(&fgraph); printf(" A corrected version was stored at %s\n", argv[2]); } } printf("\n**********************************************************************\n"); FreeGraph(&graph); gk_free((void **) ¶ms.filename, ¶ms.tpwgtsfile, ¶ms.tpwgts, LTERM); }
/*F GenerateSingleMolecule(bind) ** ** DESCRIPTION ** bind: The bind structure (for molecule and reaction data) ** ** REMARKS ** ** Top routine to generate a single molecule from a ** specification ** ** ** REFERENCES ** ** SEE ALSO ** ** HEADERFILE ** */ extern INT GenerateSetOfMolecules(BindStructure *bind) { CommandMaster *commandmaster; GenerateStructureMaster *specmaster; INT num,i; SetOfGraphs *set; MoleculeSet *mols; MoleculeSet *molecules,*newmols; BaseArgumentType *currentvalue; Graph *graph,*graphelement; molecules = GetBoundStructure(bind,BIND_CURRENT_MOLECULES); commandmaster = GetBoundStructure(bind,BIND_COMMANDMASTER); specmaster = GetBoundStructure(bind,BIND_GENERATE); currentvalue = GetCurrentArgument("NumberOfMolecules",commandmaster); num = currentvalue->Integer_Value; set = AllocateSetOfGraphs; CreateSetOfGraphs(set,commandmaster->ID,commandmaster->Name, num,0); graphelement = set->Graphs; for(i=0;i<num;i++) { graph = GenerateSingleMoleculeAsGraph(specmaster); CopyFullGraph(graphelement,graph); FreeGraph(graph); graphelement++; } mols = TransferSetOfGraphsToMoleculeSet(set); newmols = MergeMoleculeSets(mols,molecules); ReplaceBindMoleculeSet(newmols,bind); return(SYSTEM_NORMAL_RETURN); }
/************************************************************************* * This function takes a graph and produces a bisection of it **************************************************************************/ idxtype MlevelKWayPartitioning(CtrlType *ctrl, GraphType *graph, idxtype nparts, idxtype *part, float *tpwgts, float ubfactor) { idxtype i, j, nvtxs, tvwgt, tpwgts2[2]; GraphType *cgraph; idxtype wgtflag=3, numflag=0, options[10], edgecut; cgraph = Coarsen2Way(ctrl, graph); IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->InitPartTmr)); AllocateKWayPartitionMemory(ctrl, cgraph, nparts); options[0] = 1; options[OPTION_CTYPE] = MTYPE_SHEMKWAY; options[OPTION_ITYPE] = ITYPE_GGPKL; options[OPTION_RTYPE] = RTYPE_FM; options[OPTION_DBGLVL] = 0; METIS_WPartGraphRecursive(&cgraph->nvtxs, cgraph->xadj, cgraph->adjncy, cgraph->vwgt, cgraph->adjwgt, &wgtflag, &numflag, &nparts, tpwgts, options, &edgecut, cgraph->where); IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->InitPartTmr)); IFSET(ctrl->dbglvl, DBG_IPART, mprintf("Initial %D-way partitioning cut: %D\n", nparts, edgecut)); IFSET(ctrl->dbglvl, DBG_KWAYPINFO, ComputePartitionInfo(cgraph, nparts, cgraph->where)); RefineKWay(ctrl, graph, cgraph, nparts, tpwgts, ubfactor); idxcopy(graph->nvtxs, graph->where, part); FreeGraph(graph, 0); return graph->mincut; }
void Project2WayNodePartition(ctrl_t *ctrl, graph_t *graph) { idx_t i, j, nvtxs; idx_t *cmap, *where, *cwhere; graph_t *cgraph; cgraph = graph->coarser; cwhere = cgraph->where; nvtxs = graph->nvtxs; cmap = graph->cmap; Allocate2WayNodePartitionMemory(ctrl, graph); where = graph->where; /* Project the partition */ for (i=0; i<nvtxs; i++) { where[i] = cwhere[cmap[i]]; ASSERTP(where[i] >= 0 && where[i] <= 2, ("%"PRIDX" %"PRIDX" %"PRIDX" %"PRIDX"\n", i, cmap[i], where[i], cwhere[cmap[i]])); } FreeGraph(&graph->coarser); graph->coarser = NULL; Compute2WayNodePartitionParams(ctrl, graph); }
void METIS_NodeRefine(int nvtxs, idxtype *xadj, idxtype *vwgt, idxtype *adjncy, idxtype *adjwgt, idxtype *where, idxtype *hmarker, float ubfactor) { GraphType *graph; CtrlType ctrl; ctrl.dbglvl = ONMETIS_DBGLVL; ctrl.optype = OP_ONMETIS; graph = CreateGraph(); SetUpGraph(graph, OP_ONMETIS, nvtxs, 1, xadj, adjncy, vwgt, adjwgt, 3); AllocateWorkSpace(&ctrl, graph, 2); Allocate2WayNodePartitionMemory(&ctrl, graph); idxcopy(nvtxs, where, graph->where); Compute2WayNodePartitionParams(&ctrl, graph); FM_2WayNodeRefine_OneSidedP(&ctrl, graph, hmarker, ubfactor, 10); /* FM_2WayNodeRefine_TwoSidedP(&ctrl, graph, hmarker, ubfactor, 10); */ FreeWorkSpace(&ctrl, graph); idxcopy(nvtxs, graph->where, where); FreeGraph(graph); }
/****************************************************************************** * This function takes a graph and its partition vector and creates a new * graph corresponding to the one after the movement *******************************************************************************/ void TestMoveGraph(graph_t *ograph, graph_t *omgraph, idx_t *part, MPI_Comm comm) { idx_t npes, mype; ctrl_t *ctrl; graph_t *graph, *mgraph; idx_t options[5] = {0, 0, 1, 0, 0}; gkMPI_Comm_size(comm, &npes); ctrl = SetupCtrl(PARMETIS_OP_KMETIS, NULL, 1, npes, NULL, NULL, comm); mype = ctrl->mype; ctrl->CoarsenTo = 1; /* Needed by SetUpGraph, otherwise we can FP errors */ graph = TestSetUpGraph(ctrl, ograph->vtxdist, ograph->xadj, NULL, ograph->adjncy, NULL, 0); AllocateWSpace(ctrl, 0); CommSetup(ctrl, graph); graph->where = part; graph->ncon = 1; mgraph = MoveGraph(ctrl, graph); omgraph->gnvtxs = mgraph->gnvtxs; omgraph->nvtxs = mgraph->nvtxs; omgraph->nedges = mgraph->nedges; omgraph->vtxdist = mgraph->vtxdist; omgraph->xadj = mgraph->xadj; omgraph->adjncy = mgraph->adjncy; mgraph->vtxdist = NULL; mgraph->xadj = NULL; mgraph->adjncy = NULL; FreeGraph(mgraph); graph->where = NULL; FreeInitialGraphAndRemap(graph); FreeCtrl(&ctrl); }
void FreeParameters(Parameters *parameters) { FreeGraph(parameters->posGraph); FreeLabelList(parameters->labelList); free(parameters->posEgsVertexIndices); free(parameters->log2Factorial); free(parameters); }
void EvaluateSub(Substructure *sub, Parameters *parameters) { double sizeOfSub; double sizeOfPosGraph; double sizeOfCompressedPosGraph; double subValue = 0.0; Graph *compressedGraph; ULONG numLabels; ULONG posEgsCovered; // parameters used Graph *posGraph = parameters->posGraph; double posGraphDL = parameters->posGraphDL; ULONG numPosEgs = parameters->numPosEgs; LabelList *labelList = parameters->labelList; BOOLEAN allowInstanceOverlap = parameters->allowInstanceOverlap; ULONG evalMethod = parameters->evalMethod; // calculate number of examples covered by this substructure sub->numExamples = PosExamplesCovered(sub, parameters); switch(evalMethod) { case EVAL_MDL: numLabels = labelList->numLabels; sizeOfSub = MDL(sub->definition, numLabels, parameters); sizeOfPosGraph = posGraphDL; // cached at beginning compressedGraph = CompressGraph(posGraph, sub->instances, parameters); numLabels++; // add one for new "SUB" vertex label if ((allowInstanceOverlap) && (InstancesOverlap(sub->instances))) numLabels++; // add one for new "OVERLAP" edge label sizeOfCompressedPosGraph = MDL(compressedGraph, numLabels, parameters); // add extra bits to describe where external edges connect to instances sizeOfCompressedPosGraph += ExternalEdgeBits(compressedGraph,sub->definition,sub->numInstances); subValue = sizeOfPosGraph / (sizeOfSub + sizeOfCompressedPosGraph); FreeGraph(compressedGraph); break; case EVAL_SIZE: sizeOfSub = (double) GraphSize(sub->definition); sizeOfPosGraph = (double) GraphSize(posGraph); sizeOfCompressedPosGraph = (double) SizeOfCompressedGraph(posGraph, sub->instances, parameters, POS); subValue = sizeOfPosGraph / (sizeOfSub + sizeOfCompressedPosGraph); break; case EVAL_SETCOVER: posEgsCovered = PosExamplesCovered(sub, parameters); subValue = ((double) (posEgsCovered)) / ((double) (numPosEgs)); break; } sub->value = subValue; }
void FreeParkingLot(ParkingLot * parkinglot) { FreeDecoder( GetDecoder( parkinglot ), GetVertices( parkinglot ) ); FreeGraph( GetGraph( parkinglot ) ) ; freeLinkedList( GetAccesses( parkinglot) ); freeLinkedList( GetQueueHead(parkinglot) ); FreeParkedCars( GetParkedListHead(parkinglot) ); free(parkinglot); }
Graph *ReadGraph(char *filename, LabelList *labelList, BOOLEAN directed) { Graph *graph; FILE *graphFile; ULONG lineNo; // Line number counter for graph file char token[TOKEN_LEN]; ULONG vertexListSize = 0; // Size of currently-allocated vertex array ULONG edgeListSize = 0; // Size of currently-allocated edge array ULONG vertexOffset = 0; // Dummy argument to ReadVertex and ReadEdge // Allocate graph graph = AllocateGraph(0,0); // Open graph file graphFile = fopen(filename,"r"); if (graphFile == NULL) { fprintf(stderr, "Unable to open graph file %s.\n", filename); exit(1); } // Parse graph file lineNo = 1; while (ReadToken(token, graphFile, &lineNo) != 0) { if (strcmp(token, "v") == 0) // read vertex ReadVertex(graph, graphFile, labelList, &vertexListSize, &lineNo, vertexOffset); else if (strcmp(token, "e") == 0) // read 'e' edge ReadEdge(graph, graphFile, labelList, &edgeListSize, &lineNo, directed, vertexOffset); else if (strcmp(token, "u") == 0) // read undirected edge ReadEdge(graph, graphFile, labelList, &edgeListSize, &lineNo, FALSE, vertexOffset); else if (strcmp(token, "d") == 0) // read directed edge ReadEdge(graph, graphFile, labelList, &edgeListSize, &lineNo, TRUE, vertexOffset); else { fclose(graphFile); FreeGraph(graph); fprintf(stderr, "Unknown token %s in line %lu of graph file %s.\n", token, lineNo, filename); exit(1); } } fclose(graphFile); //***** trim vertex, edge and label lists return graph; }
/*F AddStructureNext(currentstructure,element) ** ** DESCRIPTION ** currentstructure: The current structure to add to ** element: The structural element to add ** ** REMARKS ** ** This connects the current structure with the structural element ** to form a new currentstructure ** ** ** REFERENCES ** ** SEE ALSO ** ** HEADERFILE ** */ static void AddStructureNext(CurrentStructure *currentstructure, FullStructuralElement *element){ INT currentattach, structureattach,replacepoint,replacepointC; CombinedGraph *combined,*newcombined; AttachmentRemoved *currentR,*elementR; CurrentStructure *elementcurrent; INT a1,a2,offset; Neighbor *n1,*n2; currentattach = PickPoint(currentstructure->Attachments->NumberOfPoints); structureattach = PickPoint(element->Connections->NumberOfPoints); elementcurrent = AllocateCurrentStructure; CreateCurrentStructure(elementcurrent,currentstructure->ID,currentstructure->Name, 0,element->MoleculeGraph,element->Connections); /* PrintPrettyGraph("current: ",stdout,currentstructure->Structure); PrintPrettyDataSubSet(stdout,"Attachments: ",currentstructure->Attachments); PrintPrettyGraph("element: ",stdout,element->MoleculeGraph); PrintPrettyDataSubSet(stdout,"Attachments: ",elementcurrent->Attachments); */ replacepoint = *(elementcurrent->Attachments->Points + structureattach); replacepointC = *(currentstructure->Attachments->Points + currentattach); printf("Remove: Element (%d,%d,%d), Current(%d,%d,%d)\n", replacepoint,structureattach,element->Connections->NumberOfPoints, replacepointC,currentattach,currentstructure->Attachments->NumberOfPoints); currentR = RemoveAttachment(currentstructure,currentattach); elementR = RemoveAttachment(elementcurrent,structureattach); /* PrintPrettyGraph("currentR: ",stdout,currentR->Structure); PrintPrettyGraph("elementR: ",stdout,elementR->Structure); */ offset = currentR->Structure->NumberOfNodes; combined = AllocateCombinedGraph; CreateCombinedGraph(combined,currentstructure->ID,currentstructure->Name, currentR->Structure, 1,0); *(combined->Begins) = 0; newcombined = AddGraphToCombined(elementR->Structure,combined); a1 = currentR->Attachment; a2 = elementR->Attachment + offset; n1 = newcombined->Combined->Neighbors + a1; n2 = newcombined->Combined->Neighbors + a2; AddElementToNeighbor(a1,n2); AddElementToNeighbor(a2,n1); FreeGraph(currentstructure->Structure); CopyFullGraph(currentstructure->Structure,newcombined->Combined); /* PrintPrettyGraph("newcombined with bond: ",stdout,currentstructure->Structure); */ offset = *(newcombined->Begins +1); AdjustAttachmentPointsOfNewElement(offset,replacepoint,replacepointC,elementcurrent,currentstructure); }
void FreeSub(Substructure *sub) { if (sub != NULL) { FreeGraph(sub->definition); FreeInstanceList(sub->instances); FreeInstanceList(sub->negInstances); free(sub); } }
void MlevelNestedDissection(ctrl_t *ctrl, graph_t *graph, idx_t *order, idx_t lastvtx) { idx_t i, j, nvtxs, nbnd; idx_t *label, *bndind; graph_t *lgraph, *rgraph; nvtxs = graph->nvtxs; MlevelNodeBisectionMultiple(ctrl, graph); IFSET(ctrl->dbglvl, METIS_DBG_SEPINFO, printf("Nvtxs: %6"PRIDX", [%6"PRIDX" %6"PRIDX" %6"PRIDX"]\n", graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2])); /* Order the nodes in the separator */ nbnd = graph->nbnd; bndind = graph->bndind; label = graph->label; for (i=0; i<nbnd; i++) order[label[bndind[i]]] = --lastvtx; SplitGraphOrder(ctrl, graph, &lgraph, &rgraph); /* Free the memory of the top level graph */ FreeGraph(&graph); /* Recurse on lgraph first, as its lastvtx depends on rgraph->nvtxs, which will not be defined upon return from MlevelNestedDissection. */ if (lgraph->nvtxs > MMDSWITCH && lgraph->nedges > 0) MlevelNestedDissection(ctrl, lgraph, order, lastvtx-rgraph->nvtxs); else { MMDOrder(ctrl, lgraph, order, lastvtx-rgraph->nvtxs); FreeGraph(&lgraph); } if (rgraph->nvtxs > MMDSWITCH && rgraph->nedges > 0) MlevelNestedDissection(ctrl, rgraph, order, lastvtx); else { MMDOrder(ctrl, rgraph, order, lastvtx); FreeGraph(&rgraph); } }
/************************************************************************* * This function is the entry point for ONWMETIS. It requires weights on the * vertices. It is for the case that the matrix has been pre-compressed. **************************************************************************/ void METIS_EdgeComputeSeparator(idxtype *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, idxtype *options, idxtype *sepsize, idxtype *part) { idxtype i, j, tvwgt, tpwgts[2]; GraphType graph; CtrlType ctrl; SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, 3); tvwgt = idxsum(*nvtxs, graph.vwgt, 1); if (options[0] == 0) { /* Use the default parameters */ ctrl.CType = ONMETIS_CTYPE; ctrl.IType = ONMETIS_ITYPE; ctrl.RType = ONMETIS_RTYPE; ctrl.dbglvl = ONMETIS_DBGLVL; } else { ctrl.CType = options[OPTION_CTYPE]; ctrl.IType = options[OPTION_ITYPE]; ctrl.RType = options[OPTION_RTYPE]; ctrl.dbglvl = options[OPTION_DBGLVL]; } ctrl.oflags = 0; ctrl.pfactor = 0; ctrl.nseps = 1; ctrl.optype = OP_OEMETIS; ctrl.CoarsenTo = amin(100, *nvtxs-1); ctrl.maxvwgt = 1.5*tvwgt/ctrl.CoarsenTo; InitRandom(options[7]); AllocateWorkSpace(&ctrl, &graph, 2); /*============================================================ * Perform the bisection *============================================================*/ tpwgts[0] = tvwgt/2; tpwgts[1] = tvwgt-tpwgts[0]; MlevelEdgeBisection(&ctrl, &graph, tpwgts, 1.05); ConstructMinCoverSeparator(&ctrl, &graph, 1.05); *sepsize = graph.pwgts[2]; idxcopy(*nvtxs, graph.where, part); FreeGraph(&graph, 0); FreeWorkSpace(&ctrl, &graph); }
/************************************************************************* * Let the game begin **************************************************************************/ int main(int argc, char *argv[]) { idx_t i; idx_t *perm, *iperm; graph_t *graph; params_t params; size_t maxlnz, opc; if (argc != 3) { printf("Usage: %s <GraphFile> <PermFile\n", argv[0]); exit(0); } params.filename = gk_strdup(argv[1]); graph = ReadGraph(¶ms); if (graph->nvtxs <= 0) { printf("Empty graph. Nothing to do.\n"); exit(0); } if (graph->ncon != 1) { printf("Ordering can only be applied to graphs with one constraint.\n"); exit(0); } /* Read the external iperm vector */ perm = imalloc(graph->nvtxs, "main: perm"); iperm = imalloc(graph->nvtxs, "main: iperm"); ReadPOVector(graph, argv[2], iperm); for (i=0; i<graph->nvtxs; i++) perm[iperm[i]] = i; printf("**********************************************************************\n"); printf("%s", METISTITLE); printf("Graph Information ---------------------------------------------------\n"); printf(" Name: %s, #Vertices: %"PRIDX", #Edges: %"PRIDX"\n\n", argv[1], graph->nvtxs, graph->nedges/2); printf("Fillin... -----------------------------------------------------------\n"); ComputeFillIn(graph, perm, iperm, &maxlnz, &opc); printf(" Nonzeros: %6.3le \tOperation Count: %6.3le\n", (double)maxlnz, (double)opc); printf("**********************************************************************\n"); FreeGraph(&graph); }
/************************************************************************* * This function takes a graph and produces a bisection of it **************************************************************************/ idxtype MCMlevelKWayPartitioning(CtrlType *ctrl, GraphType *graph, idxtype nparts, idxtype *part, float *rubvec) { idxtype i, j, nvtxs; GraphType *cgraph; idxtype options[10], edgecut; cgraph = MCCoarsen2Way(ctrl, graph); IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->InitPartTmr)); MocAllocateKWayPartitionMemory(ctrl, cgraph, nparts); options[0] = 1; options[OPTION_CTYPE] = MTYPE_SBHEM_INFNORM; options[OPTION_ITYPE] = ITYPE_RANDOM; options[OPTION_RTYPE] = RTYPE_FM; options[OPTION_DBGLVL] = 0; /* Determine what you will use as the initial partitioner, based on tolerances */ for (i=0; i<graph->ncon; i++) { if (rubvec[i] > 1.2) break; } if (i == graph->ncon) METIS_mCPartGraphRecursiveInternal(&cgraph->nvtxs, &cgraph->ncon, cgraph->xadj, cgraph->adjncy, cgraph->nvwgt, cgraph->adjwgt, &nparts, options, &edgecut, cgraph->where); else METIS_mCHPartGraphRecursiveInternal(&cgraph->nvtxs, &cgraph->ncon, cgraph->xadj, cgraph->adjncy, cgraph->nvwgt, cgraph->adjwgt, &nparts, rubvec, options, &edgecut, cgraph->where); IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->InitPartTmr)); IFSET(ctrl->dbglvl, DBG_IPART, mprintf("Initial %D-way partitioning cut: %D\n", nparts, edgecut)); IFSET(ctrl->dbglvl, DBG_KWAYPINFO, ComputePartitionInfo(cgraph, nparts, cgraph->where)); MocRefineKWayHorizontal(ctrl, graph, cgraph, nparts, rubvec); idxcopy(graph->nvtxs, graph->where, part); FreeGraph(graph, 0); return graph->mincut; }
InstanceList *FilterInstances(Graph *subGraph, InstanceList *instanceList, Graph *graph, Parameters *parameters) { InstanceListNode *instanceListNode; Instance *instance; InstanceList *newInstanceList; Graph *instanceGraph; double thresholdLimit; double matchCost; newInstanceList = AllocateInstanceList(); if (instanceList != NULL) { instanceListNode = instanceList->head; while (instanceListNode != NULL) { if (instanceListNode->instance != NULL) { instance = instanceListNode->instance; if (parameters->allowInstanceOverlap || (! InstanceListOverlap(instance, newInstanceList))) { thresholdLimit = parameters->threshold * (instance->numVertices + instance->numEdges); instanceGraph = InstanceToGraph(instance, graph); if (GraphMatch(subGraph, instanceGraph, parameters->labelList, thresholdLimit, & matchCost, NULL)) { if (matchCost < instance->minMatchCost) instance->minMatchCost = matchCost; InstanceListInsert(instance, newInstanceList, FALSE); } FreeGraph(instanceGraph); } } instanceListNode = instanceListNode->next; } } FreeInstanceList(instanceList); return newInstanceList; }
/****************************************************************************** * This function takes a graph and its partition vector and creates a new * graph corresponding to the one after the movement *******************************************************************************/ void TestMoveGraph(GraphType *ograph, GraphType *omgraph, idxtype *part, MPI_Comm comm) { int npes, mype; CtrlType ctrl; WorkSpaceType wspace; GraphType *graph, *mgraph; int options[5] = {0, 0, 1, 0, 0}; MPI_Comm_size(comm, &npes); MPI_Comm_rank(comm, &mype); SetUpCtrl(&ctrl, npes, 0, comm); ctrl.CoarsenTo = 1; /* Needed by SetUpGraph, otherwise we can FP errors */ graph = SetUpGraph(&ctrl, ograph->vtxdist, ograph->xadj, NULL, ograph->adjncy, NULL, 0); AllocateWSpace(&ctrl, graph, &wspace); SetUp(&ctrl, graph, &wspace); graph->where = part; graph->ncon = 1; mgraph = Mc_MoveGraph(&ctrl, graph, &wspace); omgraph->gnvtxs = mgraph->gnvtxs; omgraph->nvtxs = mgraph->nvtxs; omgraph->nedges = mgraph->nedges; omgraph->vtxdist = mgraph->vtxdist; omgraph->xadj = mgraph->xadj; omgraph->adjncy = mgraph->adjncy; mgraph->vtxdist = NULL; mgraph->xadj = NULL; mgraph->adjncy = NULL; FreeGraph(mgraph); graph->where = NULL; FreeInitialGraphAndRemap(graph, 0, 1); FreeWSpace(&wspace); }
void ProjectKWayPartition(ctrl_t *ctrl, graph_t *graph) { idx_t i, j, k, nvtxs, nbnd, nparts, me, other, istart, iend, tid, ted; idx_t *xadj, *adjncy, *adjwgt; idx_t *cmap, *where, *bndptr, *bndind, *cwhere, *htable; graph_t *cgraph; WCOREPUSH; nparts = ctrl->nparts; cgraph = graph->coarser; cwhere = cgraph->where; nvtxs = graph->nvtxs; cmap = graph->cmap; xadj = graph->xadj; adjncy = graph->adjncy; adjwgt = graph->adjwgt; AllocateKWayPartitionMemory(ctrl, graph); where = graph->where; bndind = graph->bndind; bndptr = iset(nvtxs, -1, graph->bndptr); htable = iset(nparts, -1, iwspacemalloc(ctrl, nparts)); /* Compute the required info for refinement */ switch (ctrl->objtype) { case METIS_OBJTYPE_CUT: ASSERT(CheckBnd2(cgraph)); { ckrinfo_t *myrinfo; cnbr_t *mynbrs; /* go through and project partition and compute id/ed for the nodes */ for (i=0; i<nvtxs; i++) { k = cmap[i]; where[i] = cwhere[k]; cmap[i] = cgraph->ckrinfo[k].ed; /* For optimization */ } memset(graph->ckrinfo, 0, sizeof(ckrinfo_t)*nvtxs); cnbrpoolReset(ctrl); for (nbnd=0, i=0; i<nvtxs; i++) { istart = xadj[i]; iend = xadj[i+1]; myrinfo = graph->ckrinfo+i; if (cmap[i] == 0) { /* Interior node. Note that cmap[i] = crinfo[cmap[i]].ed */ for (tid=0, j=istart; j<iend; j++) tid += adjwgt[j]; myrinfo->id = tid; myrinfo->inbr = -1; } else { /* Potentially an interface node */ myrinfo->inbr = cnbrpoolGetNext(ctrl, iend-istart+1); mynbrs = ctrl->cnbrpool + myrinfo->inbr; me = where[i]; for (tid=0, ted=0, j=istart; j<iend; j++) { other = where[adjncy[j]]; if (me == other) { tid += adjwgt[j]; } else { ted += adjwgt[j]; if ((k = htable[other]) == -1) { htable[other] = myrinfo->nnbrs; mynbrs[myrinfo->nnbrs].pid = other; mynbrs[myrinfo->nnbrs++].ed = adjwgt[j]; } else { mynbrs[k].ed += adjwgt[j]; } } } myrinfo->id = tid; myrinfo->ed = ted; /* Remove space for edegrees if it was interior */ if (ted == 0) { ctrl->nbrpoolcpos -= iend-istart+1; myrinfo->inbr = -1; } else { if (ted-tid >= 0) BNDInsert(nbnd, bndind, bndptr, i); for (j=0; j<myrinfo->nnbrs; j++) htable[mynbrs[j].pid] = -1; } } } graph->nbnd = nbnd; } ASSERT(CheckBnd2(graph)); break; case METIS_OBJTYPE_VOL: { vkrinfo_t *myrinfo; vnbr_t *mynbrs; ASSERT(cgraph->minvol == ComputeVolume(cgraph, cgraph->where)); /* go through and project partition and compute id/ed for the nodes */ for (i=0; i<nvtxs; i++) { k = cmap[i]; where[i] = cwhere[k]; cmap[i] = cgraph->vkrinfo[k].ned; /* For optimization */ } memset(graph->vkrinfo, 0, sizeof(vkrinfo_t)*nvtxs); vnbrpoolReset(ctrl); for (i=0; i<nvtxs; i++) { istart = xadj[i]; iend = xadj[i+1]; myrinfo = graph->vkrinfo+i; if (cmap[i] == 0) { /* Note that cmap[i] = crinfo[cmap[i]].ed */ myrinfo->nid = iend-istart; myrinfo->inbr = -1; } else { /* Potentially an interface node */ myrinfo->inbr = vnbrpoolGetNext(ctrl, iend-istart+1); mynbrs = ctrl->vnbrpool + myrinfo->inbr; me = where[i]; for (tid=0, ted=0, j=istart; j<iend; j++) { other = where[adjncy[j]]; if (me == other) { tid++; } else { ted++; if ((k = htable[other]) == -1) { htable[other] = myrinfo->nnbrs; mynbrs[myrinfo->nnbrs].gv = 0; mynbrs[myrinfo->nnbrs].pid = other; mynbrs[myrinfo->nnbrs++].ned = 1; } else { mynbrs[k].ned++; } } } myrinfo->nid = tid; myrinfo->ned = ted; /* Remove space for edegrees if it was interior */ if (ted == 0) { ctrl->nbrpoolcpos -= iend-istart+1; myrinfo->inbr = -1; } else { for (j=0; j<myrinfo->nnbrs; j++) htable[mynbrs[j].pid] = -1; } } } ComputeKWayVolGains(ctrl, graph); ASSERT(graph->minvol == ComputeVolume(graph, graph->where)); } break; default: gk_errexit(SIGERR, "Unknown objtype of %d\n", ctrl->objtype); } graph->mincut = cgraph->mincut; icopy(nparts*graph->ncon, cgraph->pwgts, graph->pwgts); FreeGraph(&graph->coarser); graph->coarser = NULL; WCOREPOP; }
/************************************************************************* * This function is the entry point of the initial partition algorithm * that does recursive bissection. * This algorithm assembles the graph to all the processors and preceeds * by parallelizing the recursive bisection step. **************************************************************************/ void InitPartition(ctrl_t *ctrl, graph_t *graph) { idx_t i, j, ncon, mype, npes, gnvtxs, ngroups; idx_t *xadj, *adjncy, *adjwgt, *vwgt; idx_t *part, *gwhere0, *gwhere1; idx_t *tmpwhere, *tmpvwgt, *tmpxadj, *tmpadjncy, *tmpadjwgt; graph_t *agraph; idx_t lnparts, fpart, fpe, lnpes; idx_t twoparts=2, moptions[METIS_NOPTIONS], edgecut, max_cut; real_t *tpwgts, *tpwgts2, *lbvec, lbsum, min_lbsum, wsum; MPI_Comm ipcomm; struct { double sum; int rank; } lpesum, gpesum; WCOREPUSH; ncon = graph->ncon; ngroups = gk_max(gk_min(RIP_SPLIT_FACTOR, ctrl->npes), 1); IFSET(ctrl->dbglvl, DBG_TIME, gkMPI_Barrier(ctrl->comm)); IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); lbvec = rwspacemalloc(ctrl, ncon); /* assemble the graph to all the processors */ agraph = AssembleAdaptiveGraph(ctrl, graph); gnvtxs = agraph->nvtxs; /* make a copy of the graph's structure for later */ xadj = icopy(gnvtxs+1, agraph->xadj, iwspacemalloc(ctrl, gnvtxs+1)); vwgt = icopy(gnvtxs*ncon, agraph->vwgt, iwspacemalloc(ctrl, gnvtxs*ncon)); adjncy = icopy(agraph->nedges, agraph->adjncy, iwspacemalloc(ctrl, agraph->nedges)); adjwgt = icopy(agraph->nedges, agraph->adjwgt, iwspacemalloc(ctrl, agraph->nedges)); part = iwspacemalloc(ctrl, gnvtxs); /* create different processor groups */ gkMPI_Comm_split(ctrl->gcomm, ctrl->mype % ngroups, 0, &ipcomm); gkMPI_Comm_rank(ipcomm, &mype); gkMPI_Comm_size(ipcomm, &npes); /* Go into the recursive bisection */ METIS_SetDefaultOptions(moptions); moptions[METIS_OPTION_SEED] = ctrl->sync + (ctrl->mype % ngroups) + 1; tpwgts = ctrl->tpwgts; tpwgts2 = rwspacemalloc(ctrl, 2*ncon); lnparts = ctrl->nparts; fpart = fpe = 0; lnpes = npes; while (lnpes > 1 && lnparts > 1) { /* determine the weights of the two partitions as a function of the weight of the target partition weights */ for (j=(lnparts>>1), i=0; i<ncon; i++) { tpwgts2[i] = rsum(j, tpwgts+fpart*ncon+i, ncon); tpwgts2[ncon+i] = rsum(lnparts-j, tpwgts+(fpart+j)*ncon+i, ncon); wsum = 1.0/(tpwgts2[i] + tpwgts2[ncon+i]); tpwgts2[i] *= wsum; tpwgts2[ncon+i] *= wsum; } METIS_PartGraphRecursive(&agraph->nvtxs, &ncon, agraph->xadj, agraph->adjncy, agraph->vwgt, NULL, agraph->adjwgt, &twoparts, tpwgts2, NULL, moptions, &edgecut, part); /* pick one of the branches */ if (mype < fpe+lnpes/2) { KeepPart(ctrl, agraph, part, 0); lnpes = lnpes/2; lnparts = lnparts/2; } else { KeepPart(ctrl, agraph, part, 1); fpart = fpart + lnparts/2; fpe = fpe + lnpes/2; lnpes = lnpes - lnpes/2; lnparts = lnparts - lnparts/2; } } gwhere0 = iset(gnvtxs, 0, iwspacemalloc(ctrl, gnvtxs)); gwhere1 = iwspacemalloc(ctrl, gnvtxs); if (lnparts == 1) { /* Case npes is greater than or equal to nparts */ /* Only the first process will assign labels (for the reduction to work) */ if (mype == fpe) { for (i=0; i<agraph->nvtxs; i++) gwhere0[agraph->label[i]] = fpart; } } else { /* Case in which npes is smaller than nparts */ /* create the normalized tpwgts for the lnparts from ctrl->tpwgts */ tpwgts = rwspacemalloc(ctrl, lnparts*ncon); for (j=0; j<ncon; j++) { for (wsum=0.0, i=0; i<lnparts; i++) { tpwgts[i*ncon+j] = ctrl->tpwgts[(fpart+i)*ncon+j]; wsum += tpwgts[i*ncon+j]; } for (wsum=1.0/wsum, i=0; i<lnparts; i++) tpwgts[i*ncon+j] *= wsum; } METIS_PartGraphKway(&agraph->nvtxs, &ncon, agraph->xadj, agraph->adjncy, agraph->vwgt, NULL, agraph->adjwgt, &lnparts, tpwgts, NULL, moptions, &edgecut, part); for (i=0; i<agraph->nvtxs; i++) gwhere0[agraph->label[i]] = fpart + part[i]; } gkMPI_Allreduce((void *)gwhere0, (void *)gwhere1, gnvtxs, IDX_T, MPI_SUM, ipcomm); if (ngroups > 1) { tmpxadj = agraph->xadj; tmpadjncy = agraph->adjncy; tmpadjwgt = agraph->adjwgt; tmpvwgt = agraph->vwgt; tmpwhere = agraph->where; agraph->xadj = xadj; agraph->adjncy = adjncy; agraph->adjwgt = adjwgt; agraph->vwgt = vwgt; agraph->where = gwhere1; agraph->vwgt = vwgt; agraph->nvtxs = gnvtxs; edgecut = ComputeSerialEdgeCut(agraph); ComputeSerialBalance(ctrl, agraph, gwhere1, lbvec); lbsum = rsum(ncon, lbvec, 1); gkMPI_Allreduce((void *)&edgecut, (void *)&max_cut, 1, IDX_T, MPI_MAX, ctrl->gcomm); gkMPI_Allreduce((void *)&lbsum, (void *)&min_lbsum, 1, REAL_T, MPI_MIN, ctrl->gcomm); lpesum.sum = lbsum; if (min_lbsum < UNBALANCE_FRACTION*ncon) { if (lbsum < UNBALANCE_FRACTION*ncon) lpesum.sum = edgecut; else lpesum.sum = max_cut; } lpesum.rank = ctrl->mype; gkMPI_Allreduce((void *)&lpesum, (void *)&gpesum, 1, MPI_DOUBLE_INT, MPI_MINLOC, ctrl->gcomm); gkMPI_Bcast((void *)gwhere1, gnvtxs, IDX_T, gpesum.rank, ctrl->gcomm); agraph->xadj = tmpxadj; agraph->adjncy = tmpadjncy; agraph->adjwgt = tmpadjwgt; agraph->vwgt = tmpvwgt; agraph->where = tmpwhere; } icopy(graph->nvtxs, gwhere1+graph->vtxdist[ctrl->mype], graph->where); FreeGraph(agraph); gkMPI_Comm_free(&ipcomm); IFSET(ctrl->dbglvl, DBG_TIME, gkMPI_Barrier(ctrl->comm)); IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); WCOREPOP; }
idx_t MlevelKWayPartitioning(ctrl_t *ctrl, graph_t *graph, idx_t *part) { idx_t i, objval=0, curobj=0, bestobj=0; real_t curbal=0.0, bestbal=0.0; graph_t *cgraph; for (i=0; i<ctrl->ncuts; i++) { cgraph = CoarsenGraph(ctrl, graph); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startwctimer(ctrl->InitPartTmr)); AllocateKWayPartitionMemory(ctrl, cgraph); /* Compute the initial partitioning */ switch (ctrl->iptype) { case METIS_IPTYPE_METISRB: FreeWorkSpace(ctrl); /* Release the work space, for the recursive metis call */ InitKWayPartitioningRB(ctrl, cgraph); AllocateWorkSpace(ctrl, graph); /* Re-allocate the work space */ break; case METIS_IPTYPE_GROW: AllocateRefinementWorkSpace(ctrl, 2*cgraph->nedges); InitKWayPartitioningGrow(ctrl, cgraph); break; default: gk_errexit(SIGERR, "Unknown iptype: %d\n", ctrl->iptype); } IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopwctimer(ctrl->InitPartTmr)); IFSET(ctrl->dbglvl, METIS_DBG_IPART, printf("Initial %"PRIDX \ "-way partitioning cut: %"PRIDX"\n", ctrl->nparts, objval)); RefineKWay(ctrl, graph, cgraph); switch (ctrl->objtype) { case METIS_OBJTYPE_CUT: curobj = graph->mincut; break; case METIS_OBJTYPE_VOL: curobj = graph->minvol; break; default: gk_errexit(SIGERR, "Unknown objtype: %d\n", ctrl->objtype); } curbal = ComputeLoadImbalanceDiff(graph, ctrl->nparts, ctrl->pijbm, ctrl->ubfactors); if (i == 0 || (curbal <= 0.0005 && bestobj > curobj) || (bestbal > 0.0005 && curbal < bestbal)) { icopy(graph->nvtxs, graph->where, part); bestobj = curobj; bestbal = curbal; } FreeRData(graph); if (bestobj == 0) break; } FreeGraph(&graph); return bestobj; }
/************************************************************************* * This function is the entry point of the initial partition algorithm * that does recursive bissection. * This algorithm assembles the graph to all the processors and preceeds * by parallelizing the recursive bisection step. **************************************************************************/ void Mc_InitPartition_RB(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace) { int i, j; int ncon, mype, npes, gnvtxs, ngroups; idxtype *xadj, *adjncy, *adjwgt, *vwgt; idxtype *part, *gwhere0, *gwhere1; idxtype *tmpwhere, *tmpvwgt, *tmpxadj, *tmpadjncy, *tmpadjwgt; GraphType *agraph; int lnparts, fpart, fpe, lnpes; int twoparts=2, numflag = 0, wgtflag = 3, moptions[10], edgecut, max_cut; float *mytpwgts, mytpwgts2[2], lbvec[MAXNCON], lbsum, min_lbsum, wsum; MPI_Comm ipcomm; struct { float sum; int rank; } lpesum, gpesum; ncon = graph->ncon; ngroups = amax(amin(RIP_SPLIT_FACTOR, ctrl->npes), 1); IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm)); IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); agraph = Mc_AssembleAdaptiveGraph(ctrl, graph, wspace); part = idxmalloc(agraph->nvtxs, "Mc_IP_RB: part"); xadj = idxmalloc(agraph->nvtxs+1, "Mc_IP_RB: xadj"); adjncy = idxmalloc(agraph->nedges, "Mc_IP_RB: adjncy"); adjwgt = idxmalloc(agraph->nedges, "Mc_IP_RB: adjwgt"); vwgt = idxmalloc(agraph->nvtxs*ncon, "Mc_IP_RB: vwgt"); idxcopy(agraph->nvtxs*ncon, agraph->vwgt, vwgt); idxcopy(agraph->nvtxs+1, agraph->xadj, xadj); idxcopy(agraph->nedges, agraph->adjncy, adjncy); idxcopy(agraph->nedges, agraph->adjwgt, adjwgt); MPI_Comm_split(ctrl->gcomm, ctrl->mype % ngroups, 0, &ipcomm); MPI_Comm_rank(ipcomm, &mype); MPI_Comm_size(ipcomm, &npes); gnvtxs = agraph->nvtxs; gwhere0 = idxsmalloc(gnvtxs, 0, "Mc_IP_RB: gwhere0"); gwhere1 = idxmalloc(gnvtxs, "Mc_IP_RB: gwhere1"); /* ADD: this assumes that tpwgts for all constraints is the same */ /* ADD: this is necessary because serial metis does not support the general case */ mytpwgts = fsmalloc(ctrl->nparts, 0.0, "mytpwgts"); for (i=0; i<ctrl->nparts; i++) for (j=0; j<ncon; j++) mytpwgts[i] += ctrl->tpwgts[i*ncon+j]; for (i=0; i<ctrl->nparts; i++) mytpwgts[i] /= (float)ncon; /* Go into the recursive bisection */ /* ADD: consider changing this to breadth-first type bisection */ moptions[0] = 0; moptions[7] = ctrl->sync + (ctrl->mype % ngroups) + 1; lnparts = ctrl->nparts; fpart = fpe = 0; lnpes = npes; while (lnpes > 1 && lnparts > 1) { /* Determine the weights of the partitions */ mytpwgts2[0] = ssum(lnparts/2, mytpwgts+fpart); mytpwgts2[1] = 1.0-mytpwgts2[0]; if (ncon == 1) METIS_WPartGraphKway2(&agraph->nvtxs, agraph->xadj, agraph->adjncy, agraph->vwgt, agraph->adjwgt, &wgtflag, &numflag, &twoparts, mytpwgts2, moptions, &edgecut, part); else { METIS_mCPartGraphRecursive2(&agraph->nvtxs, &ncon, agraph->xadj, agraph->adjncy, agraph->vwgt, agraph->adjwgt, &wgtflag, &numflag, &twoparts, mytpwgts2, moptions, &edgecut, part); } wsum = ssum(lnparts/2, mytpwgts+fpart); sscale(lnparts/2, 1.0/wsum, mytpwgts+fpart); sscale(lnparts-lnparts/2, 1.0/(1.0-wsum), mytpwgts+fpart+lnparts/2); /* I'm picking the left branch */ if (mype < fpe+lnpes/2) { Mc_KeepPart(agraph, wspace, part, 0); lnpes = lnpes/2; lnparts = lnparts/2; } else { Mc_KeepPart(agraph, wspace, part, 1); fpart = fpart + lnparts/2; fpe = fpe + lnpes/2; lnpes = lnpes - lnpes/2; lnparts = lnparts - lnparts/2; } } /* In case npes is greater than or equal to nparts */ if (lnparts == 1) { /* Only the first process will assign labels (for the reduction to work) */ if (mype == fpe) { for (i=0; i<agraph->nvtxs; i++) gwhere0[agraph->label[i]] = fpart; } } /* In case npes is smaller than nparts */ else { if (ncon == 1) METIS_WPartGraphKway2(&agraph->nvtxs, agraph->xadj, agraph->adjncy, agraph->vwgt, agraph->adjwgt, &wgtflag, &numflag, &lnparts, mytpwgts+fpart, moptions, &edgecut, part); else METIS_mCPartGraphRecursive2(&agraph->nvtxs, &ncon, agraph->xadj, agraph->adjncy, agraph->vwgt, agraph->adjwgt, &wgtflag, &numflag, &lnparts, mytpwgts+fpart, moptions, &edgecut, part); for (i=0; i<agraph->nvtxs; i++) gwhere0[agraph->label[i]] = fpart + part[i]; } MPI_Allreduce((void *)gwhere0, (void *)gwhere1, gnvtxs, IDX_DATATYPE, MPI_SUM, ipcomm); if (ngroups > 1) { tmpxadj = agraph->xadj; tmpadjncy = agraph->adjncy; tmpadjwgt = agraph->adjwgt; tmpvwgt = agraph->vwgt; tmpwhere = agraph->where; agraph->xadj = xadj; agraph->adjncy = adjncy; agraph->adjwgt = adjwgt; agraph->vwgt = vwgt; agraph->where = gwhere1; agraph->vwgt = vwgt; agraph->nvtxs = gnvtxs; Mc_ComputeSerialBalance(ctrl, agraph, gwhere1, lbvec); lbsum = ssum(ncon, lbvec); edgecut = ComputeSerialEdgeCut(agraph); MPI_Allreduce((void *)&edgecut, (void *)&max_cut, 1, MPI_INT, MPI_MAX, ctrl->gcomm); MPI_Allreduce((void *)&lbsum, (void *)&min_lbsum, 1, MPI_FLOAT, MPI_MIN, ctrl->gcomm); lpesum.sum = lbsum; if (min_lbsum < UNBALANCE_FRACTION * (float)(ncon)) { if (lbsum < UNBALANCE_FRACTION * (float)(ncon)) lpesum.sum = (float) (edgecut); else lpesum.sum = (float) (max_cut); } MPI_Comm_rank(ctrl->gcomm, &(lpesum.rank)); MPI_Allreduce((void *)&lpesum, (void *)&gpesum, 1, MPI_FLOAT_INT, MPI_MINLOC, ctrl->gcomm); MPI_Bcast((void *)gwhere1, gnvtxs, IDX_DATATYPE, gpesum.rank, ctrl->gcomm); agraph->xadj = tmpxadj; agraph->adjncy = tmpadjncy; agraph->adjwgt = tmpadjwgt; agraph->vwgt = tmpvwgt; agraph->where = tmpwhere; } idxcopy(graph->nvtxs, gwhere1+graph->vtxdist[ctrl->mype], graph->where); FreeGraph(agraph); MPI_Comm_free(&ipcomm); GKfree((void **)&gwhere0, (void **)&gwhere1, (void **)&mytpwgts, (void **)&part, (void **)&xadj, (void **)&adjncy, (void **)&adjwgt, (void **)&vwgt, LTERM); IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm)); IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); }
//--------------------------------------------------------------------------- // // NAME: AddNegInstancesToSub // // INPUTS: (Substructure *sub) - substructure to collect instances // (Instance *subInstance) - instance of substructure // (InstanceList *instanceList) - instances to collect from in // negative graph // (Parameters *parameters) // // RETURN: (void) // // PURPOSE: Add instance from instanceList to sub's negative // instances if the instance matches sub's definition. If // allowInstanceOverlap=FALSE, then instances added only if they do // not overlap with existing instances. //--------------------------------------------------------------------------- void AddNegInstancesToSub(Substructure *sub, Instance *subInstance, InstanceList *instanceList, Parameters *parameters) { InstanceListNode *instanceListNode; Instance *instance; Graph *instanceGraph; double thresholdLimit; double matchCost; // parameters used Graph *negGraph = parameters->negGraph; LabelList *labelList = parameters->labelList; BOOLEAN allowInstanceOverlap = parameters->allowInstanceOverlap; double threshold = parameters->threshold; // collect negative instances of substructure if (instanceList != NULL) { sub->negInstances = AllocateInstanceList(); instanceListNode = instanceList->head; while (instanceListNode != NULL) { if (instanceListNode->instance != NULL) { instance = instanceListNode->instance; if (allowInstanceOverlap || (! InstanceListOverlap(instance, sub->negInstances))) { thresholdLimit = threshold * (instance->numVertices + instance->numEdges); instanceGraph = InstanceToGraph(instance, negGraph); // // First, if the threshold is 0.0, see if we can match on // just the new edge that was added. // if (threshold == 0.0) { // If instance has already been added to another substructure's // list of instances, we can skip it if (!instance->used) { if (NewEdgeMatch (sub->definition, subInstance, instanceGraph, instance, parameters, thresholdLimit, & matchCost)) { if (matchCost < instance->minMatchCost) instance->minMatchCost = matchCost; instance->used = TRUE; InstanceListInsert(instance, sub->negInstances, FALSE); sub->numNegInstances++; } } } else { if (GraphMatch(sub->definition, instanceGraph, labelList, thresholdLimit, & matchCost, NULL)) { if (matchCost < instance->minMatchCost) instance->minMatchCost = matchCost; InstanceListInsert(instance, sub->negInstances, FALSE); sub->numNegInstances++; } } FreeGraph(instanceGraph); } } instanceListNode = instanceListNode->next; } } }
/************************************************************************* * This function projects a partition, and at the same time computes the * parameters for refinement. **************************************************************************/ void MocProject2WayPartition(CtrlType *ctrl, GraphType *graph) { int i, j, k, nvtxs, nbnd, me; idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum; idxtype *cmap, *where, *id, *ed, *bndptr, *bndind; idxtype *cwhere, *cid, *ced, *cbndptr; GraphType *cgraph; cgraph = graph->coarser; cwhere = cgraph->where; cid = cgraph->id; ced = cgraph->ed; cbndptr = cgraph->bndptr; nvtxs = graph->nvtxs; cmap = graph->cmap; xadj = graph->xadj; adjncy = graph->adjncy; adjwgt = graph->adjwgt; adjwgtsum = graph->adjwgtsum; MocAllocate2WayPartitionMemory(ctrl, graph); where = graph->where; id = idxset(nvtxs, 0, graph->id); ed = idxset(nvtxs, 0, graph->ed); bndptr = idxset(nvtxs, -1, graph->bndptr); bndind = graph->bndind; /* Go through and project partition and compute id/ed for the nodes */ for (i=0; i<nvtxs; i++) { k = cmap[i]; where[i] = cwhere[k]; cmap[i] = cbndptr[k]; } for (nbnd=0, i=0; i<nvtxs; i++) { me = where[i]; id[i] = adjwgtsum[i]; if (xadj[i] == xadj[i+1]) { bndptr[i] = nbnd; bndind[nbnd++] = i; } else { if (cmap[i] != -1) { /* If it is an interface node. Note that cmap[i] = cbndptr[cmap[i]] */ for (j=xadj[i]; j<xadj[i+1]; j++) { if (me != where[adjncy[j]]) ed[i] += adjwgt[j]; } id[i] -= ed[i]; if (ed[i] > 0 || xadj[i] == xadj[i+1]) { bndptr[i] = nbnd; bndind[nbnd++] = i; } } } } graph->mincut = cgraph->mincut; graph->nbnd = nbnd; scopy(2*graph->ncon, cgraph->npwgts, graph->npwgts); FreeGraph(graph->coarser); graph->coarser = NULL; }
//--------------------------------------------------------------------------- // // NAME: AddPosInstancesToSub // // INPUTS: (Substructure *sub) - substructure to collect instances // (Instance *subInstance) - instance of substructure // (InstanceList *instanceList) - instances to collect from in // positive graph // (Parameters *parameters) // (ULONG index) - index of substructure into instance list // // RETURN: (void) // // PURPOSE: Add instance from instanceList to sub's positive // instances if the instance matches sub's definition. If // allowInstanceOverlap=FALSE, then instances added only if they do // not overlap with existing instances. //--------------------------------------------------------------------------- void AddPosInstancesToSub(Substructure *sub, Instance *subInstance, InstanceList *instanceList, Parameters *parameters, ULONG index) { InstanceListNode *instanceListNode; Instance *instance; Graph *instanceGraph; double thresholdLimit; double matchCost; ULONG counter = 0; // parameters used Graph *posGraph = parameters->posGraph; LabelList *labelList = parameters->labelList; BOOLEAN allowInstanceOverlap = parameters->allowInstanceOverlap; double threshold = parameters->threshold; // collect positive instances of substructure if (instanceList != NULL) { sub->instances = AllocateInstanceList(); // // Go ahead an insert the subInstance onto the list of instances for the // substructure, as it is obviously an instance. // subInstance->used = TRUE; InstanceListInsert(subInstance, sub->instances, FALSE); sub->numInstances++; instanceListNode = instanceList->head; while (instanceListNode != NULL) { if (instanceListNode->instance != NULL) { instance = instanceListNode->instance; if (allowInstanceOverlap || (! InstanceListOverlap(instance, sub->instances))) { thresholdLimit = threshold * (instance->numVertices + instance->numEdges); instanceGraph = InstanceToGraph(instance, posGraph); // // First, if the threshold is 0.0, see if we can match on // just the new edge that was added. // if (threshold == 0.0) { // // To avoid processing duplicates, skip all entries // before this instance (because they have been checked // before in a previous call), and skip itself (because // there is no point in comparing it to itself). // // Also, skip processing this instance if it is already // matched with another substructure. // if ((counter > index) && (!instance->used)) { if (NewEdgeMatch (sub->definition, subInstance, instanceGraph, instance, parameters, thresholdLimit, & matchCost)) { if (matchCost < instance->minMatchCost) instance->minMatchCost = matchCost; instance->used = TRUE; InstanceListInsert(instance, sub->instances, FALSE); sub->numInstances++; } } } else { if (GraphMatch(sub->definition, instanceGraph, labelList, thresholdLimit, & matchCost, NULL)) { if (matchCost < instance->minMatchCost) instance->minMatchCost = matchCost; InstanceListInsert(instance, sub->instances, FALSE); sub->numInstances++; } } FreeGraph(instanceGraph); } counter++; } instanceListNode = instanceListNode->next; } } }
void Test(char *subsFileName, char *graphFileName, Parameters *parameters, ULONG *TPp, ULONG *TNp, ULONG *FPp, ULONG *FNp) { FILE *graphFile; LabelList *labelList; BOOLEAN directed; Graph **subGraphs; ULONG numSubGraphs; Graph *graph; BOOLEAN positive1; BOOLEAN positive2; ULONG vertexOffset = 0; ULONG lineNo = 1; char token[TOKEN_LEN]; ULONG FP = 0; ULONG FN = 0; ULONG TP = 0; ULONG TN = 0; ULONG i; labelList = parameters->labelList; directed = parameters->directed; // read substructures subGraphs = ReadSubGraphsFromFile(subsFileName, SUB_TOKEN, &numSubGraphs, parameters); fprintf(stdout, "Read %lu substructures from file %s.\n", numSubGraphs, subsFileName); // open example graphs file and compute stats graphFile = fopen(graphFileName, "r"); if (graphFile == NULL) { fprintf(stderr, "Unable to open graph file %s.\n", graphFileName); exit(1); } graph = NULL; positive1 = TRUE; while (ReadToken(token, graphFile, &lineNo) != 0) { if (strcmp(token, POS_EG_TOKEN) == 0) { // reading positive eg if (graph != NULL) { // test last graph positive2 = PositiveExample(graph, subGraphs, numSubGraphs, parameters); // increment appropriate counter if (positive1 && positive2) TP++; if (positive1 && (! positive2)) FN++; if ((! positive1) && positive2) FP++; if ((! positive1) && (! positive2)) TN++; FreeGraph(graph); } graph = AllocateGraph(0,0); positive1 = TRUE; } else if (strcmp(token, NEG_EG_TOKEN) == 0) { // reading negative eg if (graph != NULL) { // test last graph positive2 = PositiveExample(graph, subGraphs, numSubGraphs, parameters); // increment appropriate counter if (positive1 && positive2) TP++; if (positive1 && (! positive2)) FN++; if ((! positive1) && positive2) FP++; if ((! positive1) && (! positive2)) TN++; FreeGraph(graph); } graph = AllocateGraph(0,0); positive1 = FALSE; } else if (strcmp(token, "v") == 0) { // read vertex if (positive1 && (graph == NULL)) { // first graph starts without positive token, so assumed positive graph = AllocateGraph(0,0); } ReadVertex(graph, graphFile, labelList, &lineNo, vertexOffset); } else if (strcmp(token, "e") == 0) // read 'e' edge ReadEdge(graph, graphFile, labelList, &lineNo, directed, vertexOffset); else if (strcmp(token, "u") == 0) // read undirected edge ReadEdge(graph, graphFile, labelList, &lineNo, FALSE, vertexOffset); else if (strcmp(token, "d") == 0) // read directed edge ReadEdge(graph, graphFile, labelList, &lineNo, TRUE, vertexOffset); else { fclose(graphFile); fprintf(stderr, "Unknown token %s in line %lu of input file %s.\n", token, lineNo, graphFileName); exit(1); } } // test last graph if (graph != NULL) { positive2 = PositiveExample(graph, subGraphs, numSubGraphs, parameters); // increment appropriate counter if (positive1 && positive2) TP++; if (positive1 && (! positive2)) FN++; if ((! positive1) && positive2) FP++; if ((! positive1) && (! positive2)) TN++; FreeGraph(graph); } fclose(graphFile); // free substructure graphs for (i = 0; i < numSubGraphs; i++) FreeGraph(subGraphs[i]); free(subGraphs); *TPp = TP; *TNp = TN; *FPp = FP; *FNp = FN; }
/************************************************************************* * This function projects a partition, and at the same time computes the * parameters for refinement. **************************************************************************/ void ProjectKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts) { int i, j, k, nvtxs, nbnd, me, other, istart, iend, ndegrees; idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum; idxtype *cmap, *where, *bndptr, *bndind; idxtype *cwhere; GraphType *cgraph; RInfoType *crinfo, *rinfo, *myrinfo; EDegreeType *myedegrees; idxtype *htable; cgraph = graph->coarser; cwhere = cgraph->where; crinfo = cgraph->rinfo; nvtxs = graph->nvtxs; cmap = graph->cmap; xadj = graph->xadj; adjncy = graph->adjncy; adjwgt = graph->adjwgt; adjwgtsum = graph->adjwgtsum; AllocateKWayPartitionMemory(ctrl, graph, nparts); where = graph->where; rinfo = graph->rinfo; bndind = graph->bndind; bndptr = idxset(nvtxs, -1, graph->bndptr); /* Go through and project partition and compute id/ed for the nodes */ for (i=0; i<nvtxs; i++) { k = cmap[i]; where[i] = cwhere[k]; cmap[i] = crinfo[k].ed; /* For optimization */ } htable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts)); ctrl->wspace.cdegree = 0; for (nbnd=0, i=0; i<nvtxs; i++) { me = where[i]; myrinfo = rinfo+i; myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0; myrinfo->edegrees = NULL; myrinfo->id = adjwgtsum[i]; if (cmap[i] > 0) { /* If it is an interface node. Note cmap[i] = crinfo[cmap[i]].ed */ istart = xadj[i]; iend = xadj[i+1]; myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; ctrl->wspace.cdegree += iend-istart; ndegrees = 0; for (j=istart; j<iend; j++) { other = where[adjncy[j]]; if (me != other) { myrinfo->ed += adjwgt[j]; if ((k = htable[other]) == -1) { htable[other] = ndegrees; myedegrees[ndegrees].pid = other; myedegrees[ndegrees++].ed = adjwgt[j]; } else { myedegrees[k].ed += adjwgt[j]; } } } myrinfo->id -= myrinfo->ed; /* Remove space for edegrees if it was interior */ if (myrinfo->ed == 0) { myrinfo->edegrees = NULL; ctrl->wspace.cdegree -= iend-istart; } else { if (myrinfo->ed-myrinfo->id >= 0) BNDInsert(nbnd, bndind, bndptr, i); myrinfo->ndegrees = ndegrees; for (j=0; j<ndegrees; j++) htable[myedegrees[j].pid] = -1; } } } idxcopy(nparts, cgraph->pwgts, graph->pwgts); graph->mincut = cgraph->mincut; graph->nbnd = nbnd; FreeGraph(graph->coarser); graph->coarser = NULL; idxwspacefree(ctrl, nparts); ASSERT(CheckBnd2(graph)); }
/*********************************************************************************** * This function is the entry point of the parallel ordering algorithm. * This function assumes that the graph is already nice partitioned among the * processors and then proceeds to perform recursive bisection. ************************************************************************************/ void ParMETIS_V3_NodeND(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *order, idxtype *sizes, MPI_Comm *comm) { int i, j; int ltvwgts[MAXNCON]; int nparts, npes, mype, wgtflag = 0, seed = GLOBAL_SEED; CtrlType ctrl; WorkSpaceType wspace; GraphType *graph, *mgraph; idxtype *morder; int minnvtxs; MPI_Comm_size(*comm, &npes); MPI_Comm_rank(*comm, &mype); nparts = npes; if (!ispow2(npes)) { if (mype == 0) printf("Error: The number of processors must be a power of 2!\n"); return; } if (vtxdist[npes] < (int)((float)(npes*npes)*1.2)) { if (mype == 0) printf("Error: Too many processors for this many vertices.\n"); return; } minnvtxs = vtxdist[1]-vtxdist[0]; for (i=0; i<npes; i++) minnvtxs = (minnvtxs < vtxdist[i+1]-vtxdist[i]) ? minnvtxs : vtxdist[i+1]-vtxdist[i]; if (minnvtxs < (int)((float)npes*1.1)) { if (mype == 0) printf("Error: vertices are not distributed equally.\n"); return; } if (*numflag == 1) ChangeNumbering(vtxdist, xadj, adjncy, order, npes, mype, 1); SetUpCtrl(&ctrl, nparts, options[PMV3_OPTION_DBGLVL], *comm); ctrl.CoarsenTo = amin(vtxdist[npes]+1, 25*npes); ctrl.CoarsenTo = amin(vtxdist[npes]+1, 25*amax(npes, nparts)); ctrl.seed = mype; ctrl.sync = seed; ctrl.partType = STATIC_PARTITION; ctrl.ps_relation = -1; ctrl.tpwgts = fsmalloc(nparts, 1.0/(float)(nparts), "tpwgts"); ctrl.ubvec[0] = 1.03; graph = Moc_SetUpGraph(&ctrl, 1, vtxdist, xadj, NULL, adjncy, NULL, &wgtflag); PreAllocateMemory(&ctrl, graph, &wspace); /*======================================================= * Compute the initial k-way partitioning =======================================================*/ IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm)); IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); Moc_Global_Partition(&ctrl, graph, &wspace); IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm)); IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); IFSET(ctrl.dbglvl, DBG_TIME, PrintTimingInfo(&ctrl)); /*======================================================= * Move the graph according to the partitioning =======================================================*/ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm)); IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.MoveTmr)); MALLOC_CHECK(NULL); graph->ncon = 1; mgraph = Moc_MoveGraph(&ctrl, graph, &wspace); MALLOC_CHECK(NULL); IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm)); IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.MoveTmr)); /*======================================================= * Now compute an ordering of the moved graph =======================================================*/ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm)); IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); FreeWSpace(&wspace); PreAllocateMemory(&ctrl, mgraph, &wspace); ctrl.ipart = ISEP_NODE; ctrl.CoarsenTo = amin(vtxdist[npes]+1, amax(20*npes, 1000)); /* compute tvwgts */ for (j=0; j<mgraph->ncon; j++) ltvwgts[j] = 0; for (i=0; i<mgraph->nvtxs; i++) for (j=0; j<mgraph->ncon; j++) ltvwgts[j] += mgraph->vwgt[i*mgraph->ncon+j]; for (j=0; j<mgraph->ncon; j++) ctrl.tvwgts[j] = GlobalSESum(&ctrl, ltvwgts[j]); mgraph->nvwgt = fmalloc(mgraph->nvtxs*mgraph->ncon, "mgraph->nvwgt"); for (i=0; i<mgraph->nvtxs; i++) for (j=0; j<mgraph->ncon; j++) mgraph->nvwgt[i*mgraph->ncon+j] = (float)(mgraph->vwgt[i*mgraph->ncon+j]) / (float)(ctrl.tvwgts[j]); morder = idxmalloc(mgraph->nvtxs, "PAROMETIS: morder"); MultilevelOrder(&ctrl, mgraph, morder, sizes, &wspace); MALLOC_CHECK(NULL); /* Invert the ordering back to the original graph */ ProjectInfoBack(&ctrl, graph, order, morder, &wspace); MALLOC_CHECK(NULL); IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm)); IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); IFSET(ctrl.dbglvl, DBG_TIME, PrintTimingInfo(&ctrl)); IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm)); free(ctrl.tpwgts); free(morder); FreeGraph(mgraph); FreeInitialGraphAndRemap(graph, 0); FreeWSpace(&wspace); FreeCtrl(&ctrl); if (*numflag == 1) ChangeNumbering(vtxdist, xadj, adjncy, order, npes, mype, 0); MALLOC_CHECK(NULL); }
/*********************************************************************************** * This function is the entry point of the parallel kmetis algorithm that uses * coordinates to compute an initial graph distribution. ************************************************************************************/ void ParMETIS_V3_PartGeomKway(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *ndims, float *xyz, int *ncon, int *nparts, float *tpwgts, float *ubvec, int *options, int *edgecut, idxtype *part, MPI_Comm *comm) { int h, i, j; int nvtxs = -1, npes, mype; int uwgtflag, cut, gcut, maxnvtxs; int ltvwgts[MAXNCON]; int moptions[10]; CtrlType ctrl; idxtype *uvwgt; WorkSpaceType wspace; GraphType *graph, *mgraph; float avg, maximb, balance, *mytpwgts; int seed, dbglvl = 0; int iwgtflag, inumflag, incon, inparts, ioptions[10]; float *itpwgts, iubvec[MAXNCON]; MPI_Comm_size(*comm, &npes); MPI_Comm_rank(*comm, &mype); /********************************/ /* Try and take care bad inputs */ /********************************/ if (options != NULL && options[0] == 1) dbglvl = options[PMV3_OPTION_DBGLVL]; CheckInputs(STATIC_PARTITION, npes, dbglvl, wgtflag, &iwgtflag, numflag, &inumflag, ncon, &incon, nparts, &inparts, tpwgts, &itpwgts, ubvec, iubvec, NULL, NULL, options, ioptions, part, comm); /*********************************/ /* Take care the nparts = 1 case */ /*********************************/ if (inparts <= 1) { idxset(vtxdist[mype+1]-vtxdist[mype], 0, part); *edgecut = 0; return; } /******************************/ /* Take care of npes = 1 case */ /******************************/ if (npes == 1 && inparts > 1) { moptions[0] = 0; nvtxs = vtxdist[1]; if (incon == 1) { METIS_WPartGraphKway(&nvtxs, xadj, adjncy, vwgt, adjwgt, &iwgtflag, &inumflag, &inparts, itpwgts, moptions, edgecut, part); } else { /* ADD: this is because METIS does not support tpwgts for all constraints */ mytpwgts = fmalloc(inparts, "mytpwgts"); for (i=0; i<inparts; i++) mytpwgts[i] = itpwgts[i*incon]; moptions[7] = -1; METIS_mCPartGraphRecursive2(&nvtxs, &incon, xadj, adjncy, vwgt, adjwgt, &iwgtflag, &inumflag, &inparts, mytpwgts, moptions, edgecut, part); free(mytpwgts); } return; } if (inumflag == 1) ChangeNumbering(vtxdist, xadj, adjncy, part, npes, mype, 1); /*****************************/ /* Set up control structures */ /*****************************/ if (ioptions[0] == 1) { dbglvl = ioptions[PMV3_OPTION_DBGLVL]; seed = ioptions[PMV3_OPTION_SEED]; } else { dbglvl = GLOBAL_DBGLVL; seed = GLOBAL_SEED; } SetUpCtrl(&ctrl, npes, dbglvl, *comm); ctrl.CoarsenTo = amin(vtxdist[npes]+1, 25*incon*amax(npes, inparts)); ctrl.seed = (seed == 0) ? mype : seed*mype; ctrl.sync = GlobalSEMax(&ctrl, seed); ctrl.partType = STATIC_PARTITION; ctrl.ps_relation = -1; ctrl.tpwgts = itpwgts; scopy(incon, iubvec, ctrl.ubvec); uwgtflag = iwgtflag|2; uvwgt = idxsmalloc(vtxdist[mype+1]-vtxdist[mype], 1, "uvwgt"); graph = Moc_SetUpGraph(&ctrl, 1, vtxdist, xadj, uvwgt, adjncy, adjwgt, &uwgtflag); free(graph->nvwgt); graph->nvwgt = NULL; PreAllocateMemory(&ctrl, graph, &wspace); /*================================================================= * Compute the initial npes-way partitioning geometric partitioning =================================================================*/ IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm)); IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); Coordinate_Partition(&ctrl, graph, *ndims, xyz, 1, &wspace); IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm)); IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); IFSET(ctrl.dbglvl, DBG_TIME, PrintTimingInfo(&ctrl)); /*================================================================= * Move the graph according to the partitioning =================================================================*/ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm)); IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.MoveTmr)); free(uvwgt); graph->vwgt = ((iwgtflag&2) != 0) ? vwgt : idxsmalloc(graph->nvtxs*incon, 1, "vwgt"); graph->ncon = incon; j = ctrl.nparts; ctrl.nparts = ctrl.npes; mgraph = Moc_MoveGraph(&ctrl, graph, &wspace); ctrl.nparts = j; /**********************************************************/ /* Do the same functionality as Moc_SetUpGraph for mgraph */ /**********************************************************/ /* compute tvwgts */ for (j=0; j<incon; j++) ltvwgts[j] = 0; for (i=0; i<graph->nvtxs; i++) for (j=0; j<incon; j++) ltvwgts[j] += mgraph->vwgt[i*incon+j]; for (j=0; j<incon; j++) ctrl.tvwgts[j] = GlobalSESum(&ctrl, ltvwgts[j]); /* check for zero wgt constraints */ for (i=0; i<incon; i++) { /* ADD: take care of the case in which tvwgts is zero */ if (ctrl.tvwgts[i] == 0) { if (ctrl.mype == 0) printf("ERROR: sum weight for constraint %d is zero\n", i); MPI_Finalize(); exit(-1); } } /* compute nvwgt */ mgraph->nvwgt = fmalloc(mgraph->nvtxs*incon, "mgraph->nvwgt"); for (i=0; i<mgraph->nvtxs; i++) for (j=0; j<incon; j++) mgraph->nvwgt[i*incon+j] = (float)(mgraph->vwgt[i*incon+j]) / (float)(ctrl.tvwgts[j]); IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm)); IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.MoveTmr)); if (ctrl.dbglvl&DBG_INFO) { cut = 0; for (i=0; i<graph->nvtxs; i++) for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++) if (graph->where[i] != graph->where[graph->adjncy[j]]) cut += graph->adjwgt[j]; gcut = GlobalSESum(&ctrl, cut)/2; maxnvtxs = GlobalSEMax(&ctrl, mgraph->nvtxs); balance = (float)(maxnvtxs)/((float)(graph->gnvtxs)/(float)(npes)); rprintf(&ctrl, "XYZ Cut: %6d \tBalance: %6.3f [%d %d %d]\n", gcut, balance, maxnvtxs, graph->gnvtxs, npes); } /*================================================================= * Set up the newly moved graph =================================================================*/ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm)); IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); ctrl.nparts = inparts; FreeWSpace(&wspace); PreAllocateMemory(&ctrl, mgraph, &wspace); /*======================================================= * Now compute the partition of the moved graph =======================================================*/ if (vtxdist[npes] < SMALLGRAPH || vtxdist[npes] < npes*20 || GlobalSESum(&ctrl, mgraph->nedges) == 0) { IFSET(ctrl.dbglvl, DBG_INFO, rprintf(&ctrl, "Partitioning a graph of size %d serially\n", vtxdist[npes])); PartitionSmallGraph(&ctrl, mgraph, &wspace); } else { Moc_Global_Partition(&ctrl, mgraph, &wspace); } ParallelReMapGraph(&ctrl, mgraph, &wspace); /* Invert the ordering back to the original graph */ ctrl.nparts = npes; ProjectInfoBack(&ctrl, graph, part, mgraph->where, &wspace); *edgecut = mgraph->mincut; IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm)); IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); /*******************/ /* Print out stats */ /*******************/ IFSET(ctrl.dbglvl, DBG_TIME, PrintTimingInfo(&ctrl)); IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm)); if (ctrl.dbglvl&DBG_INFO) { rprintf(&ctrl, "Final %d-way CUT: %6d \tBalance: ", inparts, mgraph->mincut); avg = 0.0; for (h=0; h<incon; h++) { maximb = 0.0; for (i=0; i<inparts; i++) maximb = amax(maximb, mgraph->gnpwgts[i*incon+h]/itpwgts[i*incon+h]); avg += maximb; rprintf(&ctrl, "%.3f ", maximb); } rprintf(&ctrl, " avg: %.3f\n", avg/(float)incon); } GKfree((void **)&itpwgts, LTERM); FreeGraph(mgraph); FreeInitialGraphAndRemap(graph, iwgtflag); FreeWSpace(&wspace); FreeCtrl(&ctrl); if (inumflag == 1) ChangeNumbering(vtxdist, xadj, adjncy, part, npes, mype, 0); }