/* * Copyright 1997, Regents of the University of Minnesota * * order.c * * This file contains the driving routines for the multilevel ordering algorithm * * Started 5/3/97 * George * * $Id: order.c,v 1.2 2003/07/21 17:18:50 karypis Exp $ * */ #define DEBUG_ORDER_ #include /************************************************************************* * This is the top level ordering routine **************************************************************************/ void MultilevelOrder(CtrlType *ctrl, GraphType *graph, idxtype *order, idxtype *sizes, WorkSpaceType *wspace) { int i, nparts, nvtxs, npes; idxtype *perm, *lastnode, *morder, *porder; GraphType *mgraph; npes = ctrl->npes; nvtxs = graph->nvtxs; perm = idxmalloc(nvtxs, "MultilevelOrder: perm"); lastnode = idxsmalloc(4*npes, -1, "MultilevelOrder: lastnode"); for (i=0; ignvtxs; idxset(nvtxs, -1, order); sizes[0] = 2*npes-1; graph->where = idxsmalloc(nvtxs, 0, "MultilevelOrder: graph->where"); for (nparts=2; nparts<=ctrl->npes; nparts*=2) { ctrl->nparts = nparts; Order_Partition(ctrl, graph, wspace); LabelSeparators(ctrl, graph, lastnode, perm, order, sizes, wspace); CompactGraph(ctrl, graph, perm, wspace); if (ctrl->CoarsenTo < 100*nparts) { ctrl->CoarsenTo = 1.5*ctrl->CoarsenTo; } ctrl->CoarsenTo = amin(ctrl->CoarsenTo, graph->gnvtxs-1); } /*----------------------------------------------------------------- / Move the graph so that each processor gets its partition -----------------------------------------------------------------*/ IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm)); IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MoveTmr)); SetUp(ctrl, graph, wspace); graph->ncon = 1; /*needed for Moc_MoveGraph */ mgraph = Moc_MoveGraph(ctrl, graph, wspace); /* Fill in the sizes[] array for the local part. Just the vtxdist of the mgraph */ for (i=0; ivtxdist[i+1]-mgraph->vtxdist[i]; porder = idxmalloc(graph->nvtxs, "MultilevelOrder: porder"); morder = idxmalloc(mgraph->nvtxs, "MultilevelOrder: morder"); IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm)); IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MoveTmr)); /* Find the local ordering */ LocalNDOrder(ctrl, mgraph, morder, lastnode[2*(ctrl->npes+ctrl->mype)]-mgraph->nvtxs, wspace); /* Project the ordering back to the before-move graph */ ProjectInfoBack(ctrl, graph, porder, morder, wspace); /* Copy the ordering from porder to order using perm */ for (i=0; invtxs; i++) { ASSERT(ctrl, order[perm[i]] == -1); order[perm[i]] = porder[i]; } FreeGraph(mgraph); GKfree((void **)&perm, (void **)&lastnode, (void **)&porder, (void **)&morder, LTERM); /* PrintVector(ctrl, 2*npes-1, 0, sizes, "SIZES"); */ } /************************************************************************* * This function is used to assign labels to the nodes in the separators * It uses the appropriate entry in the lastnode array to select label * boundaries and adjusts it for the next level **************************************************************************/ void LabelSeparators(CtrlType *ctrl, GraphType *graph, idxtype *lastnode, idxtype *perm, idxtype *order, idxtype *sizes, WorkSpaceType *wspace) { int i, nvtxs, nparts, sid; idxtype *where, *lpwgts, *gpwgts, *sizescan; nparts = ctrl->nparts; nvtxs = graph->nvtxs; where = graph->where; lpwgts = graph->lpwgts; gpwgts = graph->gpwgts; /* Compute the local size of the separator. This is required in case the * graph has vertex weights */ idxset(2*nparts, 0, lpwgts); for (i=0; icomm); MPI_Allreduce((void *)lpwgts, (void *)gpwgts, 2*nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm); #ifdef DEBUG_ORDER PrintVector(ctrl, 2*nparts, 0, lpwgts, "Lpwgts"); PrintVector(ctrl, 2*nparts, 0, sizescan, "SizeScan"); PrintVector(ctrl, 2*nparts, 0, lastnode, "LastNode"); #endif /* Fillin the sizes[] array */ for (i=nparts-2; i>=0; i-=2) sizes[--sizes[0]] = gpwgts[nparts+i]; if (ctrl->dbglvl&DBG_INFO) { if (ctrl->mype == 0) { printf("SepSizes: "); for (i=0; icomm); } for (i=0; i<2*nparts; i++) sizescan[i] -= lpwgts[i]; for (i=0; i= nparts) { sid = where[i]; sizescan[sid]++; ASSERT(ctrl, order[perm[i]] == -1); order[perm[i]] = lastnode[sid] - sizescan[sid]; /* myprintf(ctrl, "order[%d] = %d, %d\n", perm[i], order[perm[i]], sid); */ } } /* Update lastnode array */ idxcopy(2*nparts, lastnode, sizescan); for (i=0; inparts; npes = ctrl->npes; nvtxs = graph->nvtxs; xadj = graph->xadj; ladjncy = graph->adjncy; adjwgt = graph->adjwgt; where = graph->where; if (graph->cmap == NULL) graph->cmap = idxmalloc(nvtxs+graph->nrecv, "CompactGraph: cmap"); cmap = graph->cmap; vtxdist = graph->vtxdist; /************************************************************* * Construct the cvtxdist of the contracted graph. Uses the fact * that lpwgts stores the local non separator vertices. **************************************************************/ cvtxdist = wspace->pv1; cnvtxs = cvtxdist[npes] = idxsum(nparts, graph->lpwgts); MPI_Allgather((void *)(cvtxdist+npes), 1, IDX_DATATYPE, (void *)cvtxdist, 1, IDX_DATATYPE, ctrl->comm); MAKECSR(i, npes, cvtxdist); #ifdef DEBUG_ORDER PrintVector(ctrl, npes+1, 0, cvtxdist, "cvtxdist"); #endif /************************************************************* * Construct the cmap vector **************************************************************/ cfirstvtx = cvtxdist[ctrl->mype]; /* Create the cmap of what you know so far locally */ for (cnvtxs=0, i=0; iindices, cmap+nvtxs); /************************************************************* * Finally, compact the graph **************************************************************/ newwhere = idxmalloc(cnvtxs, "CompactGraph: newwhere"); cnvtxs = l = 0; for (i=0; ivwgt[cnvtxs] = graph->vwgt[i]; newwhere[cnvtxs] = where[i]; cnvtxs++; } } for (i=cnvtxs; i>0; i--) xadj[i] = xadj[i-1]; xadj[0] = 0; GKfree((void **)&graph->match, (void **)&graph->cmap, (void **)&graph->lperm, (void **)&graph->where, (void **)&graph->label, (void **)&graph->rinfo, (void **)&graph->nrinfo, (void **)&graph->lpwgts, (void **)&graph->gpwgts, (void **)&graph->sepind, (void **)&graph->peind, (void **)&graph->sendptr, (void **)&graph->sendind, (void **)&graph->recvptr, (void **)&graph->recvind, (void **)&graph->imap, (void **)&graph->rlens, (void **)&graph->slens, (void **)&graph->rcand, (void **)&graph->pexadj, (void **)&graph->peadjncy, (void **)&graph->peadjloc, LTERM); graph->nvtxs = cnvtxs; graph->nedges = l; graph->gnvtxs = cvtxdist[npes]; idxcopy(npes+1, cvtxdist, graph->vtxdist); graph->where = newwhere; } /************************************************************************* * This function orders the locally stored graph using MMD. * The vertices will be ordered from firstnode onwards. **************************************************************************/ void LocalNDOrder(CtrlType *ctrl, GraphType *graph, idxtype *order, int firstnode, WorkSpaceType *wspace) { int i, j, nvtxs, firstvtx, lastvtx; idxtype *xadj, *adjncy; idxtype *perm, *iperm; int numflag=0, options[10]; nvtxs = graph->nvtxs; xadj = graph->xadj; adjncy = graph->adjncy; firstvtx = graph->vtxdist[ctrl->mype]; lastvtx = graph->vtxdist[ctrl->mype+1]; /* Relabel the vertices so that they are in local index space */ for (i=0; i=firstvtx && adjncy[j]maxcore); perm = wspace->core; iperm = perm + nvtxs + 5; options[0] = 0; METIS_NodeND(&nvtxs, xadj, adjncy, &numflag, options, perm, iperm); for (i=0; i=0 && iperm[i]ncon = 1; IFSET(ctrl->dbglvl, DBG_PROGRESS, rprintf(ctrl, "[%6d %8d %5d %5d][%d][%d]\n", graph->gnvtxs, GlobalSESum(ctrl, graph->nedges), GlobalSEMin(ctrl, graph->nvtxs), GlobalSEMax(ctrl, graph->nvtxs), ctrl->CoarsenTo, GlobalSEMax(ctrl, graph->vwgt[idxamax(graph->nvtxs, graph->vwgt)]))); if (graph->gnvtxs < 1.3*ctrl->CoarsenTo || (graph->finer != NULL && graph->gnvtxs > graph->finer->gnvtxs*COARSEN_FRACTION)) { /* Compute the initial npart-way multisection */ InitMultisection(ctrl, graph, wspace); if (graph->finer == NULL) { /* Do that only of no-coarsening took place */ ComputeNodePartitionParams(ctrl, graph, wspace); KWayNodeRefine(ctrl, graph, wspace, 2*NGR_PASSES, ORDER_UNBALANCE_FRACTION); } } else { /* Coarsen it and the partition it */ Mc_LocalMatch_HEM(ctrl, graph, wspace); Order_Partition(ctrl, graph->coarser, wspace); Moc_ProjectPartition(ctrl, graph, wspace); ComputeNodePartitionParams(ctrl, graph, wspace); KWayNodeRefine(ctrl, graph, wspace, 2*NGR_PASSES, ORDER_UNBALANCE_FRACTION); } }