/************************************************************************* * This function takes a graph and produces a bisection of it **************************************************************************/ int MlevelKWayPartitioning(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, float *tpwgts, float ubfactor) { int i, j, nvtxs, tvwgt, tpwgts2[2]; GraphType *cgraph; int wgtflag=3, numflag=0, options[10], edgecut; cgraph = Coarsen2Way(ctrl, graph); IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); AllocateKWayPartitionMemory(ctrl, cgraph, nparts); options[0] = 1; options[OPTION_CTYPE] = MATCH_SHEMKWAY; options[OPTION_ITYPE] = IPART_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, stoptimer(ctrl->InitPartTmr)); IFSET(ctrl->dbglvl, DBG_IPART, printf("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); GKfree(&graph->gdata, &graph->rdata, LTERM); return graph->mincut; }
/************************************************************************* * This function performs multilevel bisection **************************************************************************/ void MlevelNodeBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor) { GraphType *cgraph; ctrl->CoarsenTo = graph->nvtxs/8; if (ctrl->CoarsenTo > 100) ctrl->CoarsenTo = 100; else if (ctrl->CoarsenTo < 40) ctrl->CoarsenTo = 40; ctrl->maxvwgt = 1.5*((tpwgts[0]+tpwgts[1])/ctrl->CoarsenTo); cgraph = Coarsen2Way(ctrl, graph); switch (ctrl->IType) { case IPART_GGPKL: Init2WayPartition(ctrl, cgraph, tpwgts, ubfactor); IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SepTmr)); Compute2WayPartitionParams(ctrl, cgraph); ConstructSeparator(ctrl, cgraph, ubfactor); IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SepTmr)); break; case IPART_GGPKLNODE: InitSeparator(ctrl, cgraph, ubfactor); break; } Refine2WayNode(ctrl, graph, cgraph, ubfactor); }
void testCoarsening(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int ct) { GraphType graph, *cgraph; CtrlType ctrl; my_SetUpGraph(&graph, *nvtxs, xadj, adjncy, vwgt, adjwgt, *wgtflag, 1); /* The last argument indicates we are setting up the original * graph */ ctrl.CoarsenTo=ct; ctrl.CType=MATCH_SHEMN; my_AllocateWorkSpace(&ctrl,&graph); cgraph = Coarsen2Way(&ctrl,&graph); do { dump_graph(cgraph); cgraph = cgraph->finer; } while ( cgraph != NULL ); }
/************************************************************************* * This function performs multilevel bisection **************************************************************************/ void MlevelEdgeBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, floattype ubfactor) { GraphType *cgraph; cgraph = Coarsen2Way(ctrl, graph); Init2WayPartition(ctrl, cgraph, tpwgts, ubfactor); Refine2Way(ctrl, graph, cgraph, tpwgts, ubfactor); /* IsConnectedSubdomain(ctrl, graph, 0); IsConnectedSubdomain(ctrl, graph, 1); */ }
/************************************************************************* * This function performs multilevel bisection. It performs multiple * bisections and selects the best. **************************************************************************/ void MlevelNodeBisectionMultiple(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor) { int i, nvtxs, cnvtxs, mincut, tmp; GraphType *cgraph; idxtype *bestwhere; if (ctrl->nseps == 1 || graph->nvtxs < (ctrl->oflags&OFLAG_COMPRESS ? 1000 : 2000)) { MlevelNodeBisection(ctrl, graph, tpwgts, ubfactor); return; } nvtxs = graph->nvtxs; if (ctrl->oflags&OFLAG_COMPRESS) { /* Multiple separators at the original graph */ bestwhere = idxmalloc(nvtxs, "MlevelNodeBisection2: bestwhere"); mincut = nvtxs; for (i=ctrl->nseps; i>0; i--) { MlevelNodeBisection(ctrl, graph, tpwgts, ubfactor); /* printf("%5d ", cgraph->mincut); */ if (graph->mincut < mincut) { mincut = graph->mincut; idxcopy(nvtxs, graph->where, bestwhere); } GKfree(&graph->rdata, LTERM); if (mincut == 0) break; } /* printf("[%5d]\n", mincut); */ Allocate2WayNodePartitionMemory(ctrl, graph); idxcopy(nvtxs, bestwhere, graph->where); free(bestwhere); Compute2WayNodePartitionParams(ctrl, graph); } else { /* Coarsen it a bit */ ctrl->CoarsenTo = nvtxs-1; cgraph = Coarsen2Way(ctrl, graph); cnvtxs = cgraph->nvtxs; bestwhere = idxmalloc(cnvtxs, "MlevelNodeBisection2: bestwhere"); mincut = nvtxs; for (i=ctrl->nseps; i>0; i--) { ctrl->CType += 20; /* This is a hack. Look at coarsen.c */ MlevelNodeBisection(ctrl, cgraph, tpwgts, ubfactor); /* printf("%5d ", cgraph->mincut); */ if (cgraph->mincut < mincut) { mincut = cgraph->mincut; idxcopy(cnvtxs, cgraph->where, bestwhere); } GKfree(&cgraph->rdata, LTERM); if (mincut == 0) break; } /* printf("[%5d]\n", mincut); */ Allocate2WayNodePartitionMemory(ctrl, cgraph); idxcopy(cnvtxs, bestwhere, cgraph->where); free(bestwhere); Compute2WayNodePartitionParams(ctrl, cgraph); Refine2WayNode(ctrl, graph, cgraph, ubfactor); } }
std::vector< std::set<idxtype> > srmclWithGraph(GraphType *graph,std::vector<std::set<idxtype> >& indices,Options opt ) { GraphType *cgraph,*t,*cgraphFinest, *cgraphCoarest; int nvtxs=graph->nvtxs; CtrlType ctrl; int levels=0; Matrix *M=NULL; int ct = ctrl.CoarsenTo = opt.coarsenTo, runMcl=0; ctrl.CType=opt.matchType; ctrl.optype=OP_KMETIS; ctrl.dbglvl=1; if ( ct < 5 ) ctrl.maxvwgt = (int) ceil( (1.5*nvtxs)/ct ); else if ( ct <= 100 ) ctrl.maxvwgt = (int) ceil( (2.0*nvtxs)/ct ); else if ( ct > 100 ) { // we can allow some imbalance here. ctrl.maxvwgt = (int) ceil( 10.0 * nvtxs/ct ); } my_AllocateWorkSpace(&ctrl,graph); cgraphCoarest = cgraph = Coarsen2Way(&ctrl,graph); FreeWorkSpace(&ctrl, graph); for(levels=0,t=cgraph ; t->finer!=NULL ; t=t->finer,levels++); int num_level = levels; printf("Coarsened %d levels\n", levels); printf("Number of vertices in coarsest graph:%d\n", cgraph->nvtxs); fflush(stdout); int times_rmcl= 1; while ( cgraph != NULL ) { Matrix *M0, *Mnew; int iters; M0=setupCanonicalMatrix(cgraph->nvtxs, cgraph->nedges, cgraph->xadj, cgraph->adjncy, cgraph->adjwgt, opt.ncutify); //do weight normalization here #ifdef TEST_OUTPUT //printf("level: %d, M0:\n",levels); //printMatrix(M0); #endif if ( cgraph->coarser == NULL ) { // if this is the coarsest graph, flow matrix is same as // the transition matrix. M=M0; // dumpMatrix(M); } if (cgraph->finer == NULL){ iters=opt.num_last_iter; cgraphFinest = cgraph; } else{ iters=opt.iter_per_level; } //printMatrix(M); Mnew=dprmcl(M,M0,cgraph, opt, iters, levels); //YK: main process! M=Mnew; if ( cgraph->finer != NULL ) //YK: map nodes to the finer graph { int nnzRefinedGraph = 2*M->nnz; if ( ctrl.CType == MATCH_POWERLAW_FC ) { int ii; nnzRefinedGraph = 0; for ( ii=0; ii<cgraph->finer->nvtxs; ii++ ) { int tx=cgraph->finer->cmap[ii]; nnzRefinedGraph += M->xadj[tx+1]-M->xadj[tx]; } } else if ( ctrl.CType == MATCH_HASH && levels <= 3 ) { int ii; nnzRefinedGraph=0; for ( ii=0; ii<cgraph->nvtxs; ii++ ) { nnzRefinedGraph += cgraph->vwgt[ii] * (M->xadj[ii+1] - M->xadj[ii]); } } // dumpMatrix(M); Mnew=propagateFlow(M,cgraph,cgraph->finer,nnzRefinedGraph); //printf("times:%d, levels:%d Mnew\n",times_rmcl, levels); //printMatrix(Mnew); if ( M != NULL ) { freeMatrix(M); } M=Mnew; } cgraph=cgraph->finer; //change to the finer graph levels--; printf("Done level %d (%d times MLR-MCL)\n", levels+1,times_rmcl); fflush(stdout); } fflush(stdout); idxtype* firstIndices = (idxtype*) malloc(sizeof(idxtype) * M->nvtxs); idxcopy(nvtxs, M->attractors, firstIndices); bool* isAttractor = (bool*) malloc(sizeof(bool) * M->nvtxs); getAttractorsForAll(M, isAttractor); int** countAttractor = (int**) malloc(sizeof(int*) * (num_level+1)); //count the number of times the node being an attractor node for(int i=0; i <= num_level ; i++){ countAttractor[i] = (int*) malloc (sizeof(int) * nvtxs); for(int j=0; j<M->nvtxs; j++){ countAttractor[i][j] = 0; } } #ifdef TEST_OUTPUT { for(int i=0; i<M->nvtxs; i++){ int level = 1, nodeIdx = i; for(cgraph = cgraphFinest; cgraph->coarser!=NULL; cgraph = cgraph->coarser, level++){ idxtype oldNodeIdx = nodeIdx; nodeIdx = cgraph->cmap[oldNodeIdx]; printf(" cmap: level:%d vid: %d to %d \n", level, oldNodeIdx+1, nodeIdx+1); } } } #endif for(int i=0; i<M->nvtxs; i++){ if(isAttractor[i]){ countAttractor[0][i]++; #ifdef TEST_OUTPUT printf("attractor vid:%d(%d times), %d-th times MLRMCL\n",i+1,countAttractor[0][i],times_rmcl);fflush(stdout); #endif int level = 1, nodeIdx = i; for(cgraph = cgraphFinest; cgraph->coarser!=NULL; cgraph = cgraph->coarser, level++){ idxtype oldNodeIdx = nodeIdx; nodeIdx = cgraph->cmap[nodeIdx]; countAttractor[level][nodeIdx]++; #ifdef TEST_OUTPUT //printf("countAttractor[%d][%d] = %d;\n", level, nodeIdx,countAttractor[level][nodeIdx]); #endif } } } //construct hash table idxtype* hashtable = idxmalloc(nvtxs,"Hashtable"); for(int i=0;i<nvtxs;i++) hashtable[i]=-1; // clear hashtable. int num_clusters = 0; //include singleton for(int i=0;i<nvtxs;i++){ if ( hashtable[firstIndices[i]] == -1){ hashtable[firstIndices[i]] = num_clusters; num_clusters++; } } /*idxtype* invHashTable = idxmalloc(num_clusters,"inverse hashtable"); //map cluster id back to the attractor id for(int i=0;i<nvtxs;i++){ if ( hashtable[firstIndices[i]] != -1){ invHashTable[hashtable[firstIndices[i]]] = firstIndices[i]; } }*/ //construct clusters std::vector< std::set<idxtype> > clusters(0); //clusters[i] contains nodes' numbers (in original graph) in cluster i for(int i=0; i<num_clusters ; i++){ std::set<idxtype> newCluster; clusters.push_back(newCluster); } for(int i=0; i<nvtxs ; i++){ if( firstIndices[i] != -1){ idxtype cID = hashtable[firstIndices[i]]; indices[i].insert(cID); if(cID == -1) continue; clusters[ cID ].insert( i ); } } idxtype* lastIndices = firstIndices; bool* lastAttractor = isAttractor; idxtype* oldHashtable = hashtable; printf("number of clusters in 1st time MLR-MCL: %d\n", num_clusters);fflush(stdout); idxtype* thisIndices = (idxtype*) malloc(sizeof(idxtype) * M->nvtxs); idxtype* newHashtable = idxmalloc(nvtxs,"newHashtable"); bool* thisAttractor = (bool*) malloc(sizeof(bool) * M->nvtxs); while(times_rmcl < opt.time_rmcl){ //do more than one times R-MCL but penalize attractor nodes (by assigning them higher inflation rate) times_rmcl++; cgraph = cgraphCoarest; for(levels=0,t=cgraph ; t->finer!=NULL ; t=t->finer,levels++); while ( cgraph != NULL ) { Matrix *M0, *Mnew; int iters; M0=setupCanonicalMatrix(cgraph->nvtxs, cgraph->nedges, cgraph->xadj, cgraph->adjncy, cgraph->adjwgt, opt.ncutify); //do weight normalization here if ( cgraph->coarser == NULL ) { M=M0; } if (cgraph->finer == NULL) iters=opt.num_last_iter; else iters=opt.iter_per_level; //Mnew=dprmcl(M,M0,cgraph, opt, iters,levels); //original Mnew=dprmcl_penalizeAttractors(M,M0,cgraph, opt, iters, levels, countAttractor); //YK: main process! M=Mnew; if ( cgraph->finer != NULL ) //YK: map nodes to the finer graph { int nnzRefinedGraph = 2*M->nnz; if ( ctrl.CType == MATCH_POWERLAW_FC ) { int ii; nnzRefinedGraph = 0; for ( ii=0; ii<cgraph->finer->nvtxs; ii++ ) { int tx=cgraph->finer->cmap[ii]; nnzRefinedGraph += M->xadj[tx+1] - M->xadj[tx]; } } else if ( ctrl.CType == MATCH_HASH && levels <= 3 ) { int ii; nnzRefinedGraph=0; for ( ii=0; ii<cgraph->nvtxs; ii++ ) { nnzRefinedGraph += cgraph->vwgt[ii] * (M->xadj[ii+1] - M->xadj[ii]); } } Mnew=propagateFlow(M,cgraph,cgraph->finer,nnzRefinedGraph); //printf("times:%d, levels:%d Mnew\n",times_rmcl, levels); //printMatrix(Mnew); if ( M != NULL ) { freeMatrix(M); } M=Mnew; } cgraph=cgraph->finer; //change to the finer graph // These two didn't get freed earlier, when we freed // gdata. levels--; printf("Done level %d (%d-th times MLR-MCL)\n", levels+1,times_rmcl);fflush(stdout); } //update clusters idxcopy(nvtxs, M->attractors, thisIndices); getAttractorsForAll(M, thisAttractor); for(int i=0; i<M->nvtxs; i++){ if(thisAttractor[i]){ countAttractor[0][i]++; #ifdef TEST_OUTPUT printf("attractor vid:%d(%d times), %d-th times MLRMCL\n",i+1,countAttractor[0][i],times_rmcl); #endif int level = 1, nodeIdx = i; for(cgraph = cgraphFinest; cgraph->coarser!=NULL; cgraph = cgraph->coarser, level++){ nodeIdx = cgraph->cmap[nodeIdx]; countAttractor[level][nodeIdx]++; } //printf("attractor:%d, times:%d\n",i+1,times_rmcl); } } //construct hash table for(int i=0;i<nvtxs;i++) newHashtable[i]=-1; // clear newHashtable. int new_num_clusters = 0 ; for(int i=0;i<nvtxs;i++){ if ( newHashtable[thisIndices[i]] == -1){ newHashtable[thisIndices[i]] = num_clusters+new_num_clusters; //cluster ID if(num_clusters+new_num_clusters == 22704 || num_clusters+new_num_clusters == 29925) printf("cluster #%d's attractor node %d\n",num_clusters+new_num_clusters,thisIndices[i]); new_num_clusters++; } } //construct clusters for(int i=0; i<new_num_clusters; i++){ std::set<idxtype>* newCluster = new std::set<idxtype>(); clusters.push_back(*newCluster); } for(int i=0; i<nvtxs ; i++){ if( thisIndices[i] != -1){ idxtype cID = newHashtable[thisIndices[i]]; indices[i].insert(cID); if(cID == -1) continue; clusters[ cID ].insert( i ); } } printf("number of clusters in %dth times MLR-MCL: %d\ttotal # clusters:%zu\n", times_rmcl, new_num_clusters,clusters.size()); num_clusters += new_num_clusters; //detect last attractor is split to multiple clusters /* double* countToCluster = (double*) malloc(sizeof(double) * num_clusters) ; for(idxtype vID=0; vID<nvtxs ; vID++){ //printf("test:%d\n",vID+1);fflush(stdout); if(lastAttractor[vID] && !thisAttractor[vID]){ for(int i=0; i<num_clusters; i++) countToCluster[i] = 0; int lastCluster = oldHashtable[lastIndices[vID]]; //printf("lastCluster:cid%d (attractor:%d size:%zu), num clusters:%d\n",lastCluster,vID+1,clusters[lastCluster].size(),num_clusters);fflush(stdout); for(std::set<idxtype>::iterator nodeIterator = clusters[lastCluster].begin(); nodeIterator != clusters[lastCluster].end(); nodeIterator++){ int currentCluster = newHashtable[thisIndices[*nodeIterator]]; countToCluster[currentCluster] ++; } for(idxtype cID = 0; cID < num_clusters; cID++){ if(countToCluster[cID] / clusters[lastCluster].size() >= opt.ratio_nodes_another_cluster && clusters[cID].find(vID)==clusters[cID].end() ){ //clusters[ cID ].insert(vID); //indices[ vID ].insert(cID); #ifdef TEST_OUTPUT printf("^add extra cluster: vid:%d to cid:%d\n",vID+1, cID);fflush(stdout); #endif } } } } free(countToCluster);*/ lastIndices = thisIndices; lastAttractor = thisAttractor; oldHashtable = newHashtable; } printf("total number of clusters after %d times MLR-MCL:%zu\n", opt.time_rmcl, clusters.size());fflush(stdout); free(hashtable); for(int i=0; i <= num_level ; i++) free(countAttractor[i]); free(countAttractor); free(isAttractor); free(firstIndices); free(thisIndices); free(newHashtable); free(thisAttractor); freeMatrix(M); return clusters; }
void mlmclWithGraph(GraphType *graph,idxtype* indices,Options opt) { GraphType *cgraph,*t; int nvtxs=graph->nvtxs; CtrlType ctrl; int levels=0; Matrix *M=NULL; int ct = ctrl.CoarsenTo = opt.coarsenTo, runMcl=0; ctrl.CType=opt.matchType; /* if ( nvtxs > 50000 ) ctrl.CType = MATCH_POWERLAW_FC; */ ctrl.optype=OP_KMETIS; // ctrl.maxvwgt = (int) round( ((ct>100)?nvtxs/100: nvtxs/ct)); // ctrl.maxvwgt = (ctrl.maxvwgt > 5000 ) ? 5000 : ctrl.maxvwgt ; ctrl.dbglvl=1; if ( ct < 5 ) ctrl.maxvwgt = (int) ceil( (1.5*nvtxs)/ct ); else if ( ct <= 100 ) ctrl.maxvwgt = (int) ceil( (2.0*nvtxs)/ct ); else if ( ct > 100 ) { // we can allow some imbalance here. ctrl.maxvwgt = (int) ceil( 10.0 * nvtxs/ct ); } my_AllocateWorkSpace(&ctrl,graph); cgraph = Coarsen2Way(&ctrl,graph); FreeWorkSpace(&ctrl, graph); // printf( "Coarsen time:%.2f\n",gettimer(ctrl.CoarsenTmr) ); for(levels=0,t=cgraph;t->finer!=NULL;t=t->finer,levels++); printf("Coarsened %d levels\n", levels); printf("Number of vertices in coarsest graph:%d\n", cgraph->nvtxs); // printf("In lib/mlmcl.c: penalty_power:%.1f\n", opt.penalty_power); fflush(stdout); while ( cgraph != NULL ) { Matrix *M0, *Mnew; int iters; // dump_graph(cgraph); M0=setupCanonicalMatrix(cgraph->nvtxs, cgraph->nedges, cgraph->xadj, cgraph->adjncy, cgraph->adjwgt, opt.ncutify); if ( cgraph->coarser != NULL ) { // if this is not the original graph, then we don't // need the adjacency information in the graph // anymore. M0 is what we want, and we have it, so we // can free cgraph->gdata. GKfree( (void**)&(cgraph->gdata), LTERM); } if ( cgraph->coarser == NULL ) { // if this is the coarsest graph, flow matrix is same as // the transition matrix. M=M0; // dumpMatrix(M); } if (cgraph->finer == NULL) iters=opt.num_last_iter; else iters=opt.iter_per_level; if ( cgraph->coarser == NULL ) {; //printRow(M,35); //printRow(M,36); } Mnew=dprmcl(M,M0,cgraph, opt, iters, levels); // M would have been freed in mclForMultiLevel, so no // need to free it here. /* if ( M0 != NULL ) { freeMatrix(M0); } */ if ( cgraph->coarser == NULL ) { //printRow(Mnew,35); //printRow(Mnew,36); } if ( runMcl > 0 && cgraph->finer == NULL ) { /* run original mcl so that the matrix moves closer to * convergence */ M=dprmcl(Mnew,Mnew,cgraph, opt, iters/2,levels); /* Mnew would not have been freed in mclForMultiLevel * above. */ freeMatrix(Mnew); } else { M=Mnew; } if ( cgraph->finer != NULL ) { int nnzRefinedGraph = 2*M->nnz; if ( ctrl.CType == MATCH_POWERLAW_FC ) { int ii; nnzRefinedGraph = 0; for ( ii=0; ii<cgraph->finer->nvtxs; ii++ ) { int tx=cgraph->finer->cmap[ii]; nnzRefinedGraph += M->xadj[tx+1]-M->xadj[tx]; } } else if ( ctrl.CType == MATCH_HASH && levels <= 3 ) { int ii; nnzRefinedGraph=0; for ( ii=0; ii<cgraph->nvtxs; ii++ ) { nnzRefinedGraph += cgraph->vwgt[ii] * (M->xadj[ii+1] - M->xadj[ii]); } } // dumpMatrix(M); Mnew=propagateFlow(M,cgraph,cgraph->finer,nnzRefinedGraph); // dumpMatrix(Mnew); if ( M != NULL ) { freeMatrix(M); } M=Mnew; } cgraph=cgraph->finer; // These two didn't get freed earlier, when we freed // gdata. if ( cgraph != NULL ) { GKfree( (void**)&(cgraph->coarser->vwgt), (void**)&(cgraph->coarser->rmap1), LTERM); } levels--; printf("Done level %d\n", levels+1); fflush(stdout); } getAttractorsForAll(M); idxcopy(nvtxs, M->attractors, indices); /* int nClusters = 0; wgttype minWgt = 0; idxtype *ret = getNodesToComponentMap(M, &nClusters, minWgt); idxcopy(nvtxs, ret, indices); free(ret); */ freeMatrix(M); }