/* * Copyright 2003, Regents of the University of Minnesota * * kmetis.c * * This file contains the top level routines for the contact-friendly partitioning * algorithm CMETIS. * * Started 4/3/03 * George * */ #include #define DEPSILON 1.0e-012 #define _PRINTSTAT /************************************************************************* * This function is the entry point for KMETIS **************************************************************************/ void *METIS_PartGraphForContact(idxtype *nvtxs, idxtype *xadj, idxtype *adjncy, double *xyzcoords, idxtype *sflag, idxtype *numflag, idxtype *nparts, idxtype *options, idxtype *edgecut, idxtype *part) { idxtype i, j, ii, dim, ncon, wgtflag, mcnumflag, nnodes, nlnodes, nclean, naclean, ndirty, maxdepth, rwgtflag, rnumflag; idxtype *mcvwgt, *dtpart, *marker, *leafpart; idxtype *adjwgt; float rubvec[2], lbvec[2]; GraphType graph, *cgraph; ContactInfoType *cinfo; DKeyValueType *xyzcand[3]; if (*numflag == 1) Change2CNumbering(*nvtxs, xadj, adjncy); /*--------------------------------------------------------------------- * Allocate memory for the contact info type *---------------------------------------------------------------------*/ cinfo = (ContactInfoType *)gk_malloc(sizeof(ContactInfoType), "METIS_PartGraphForContact: cinfo"); cinfo->leafptr = idxsmalloc(*nvtxs+1, 0, "METIS_PartGraphForContact: leafptr"); cinfo->leafind = idxsmalloc(*nvtxs, 0, "METIS_PartGraphForContact: leafind"); cinfo->leafwgt = idxsmalloc(*nvtxs, 0, "METIS_PartGraphForContact: leafwgt"); cinfo->part = idxsmalloc(*nvtxs, 0, "METIS_PartGraphForContact: part"); leafpart = cinfo->leafpart = idxmalloc(*nvtxs, "METIS_PartGraphForContact: leafpart"); cinfo->dtree = (DTreeNodeType *)gk_malloc(sizeof(DTreeNodeType)*(*nvtxs), "METIS_PartGraphForContact: cinfo->dtree"); cinfo->nvtxs = *nvtxs; /*--------------------------------------------------------------------- * Compute the initial k-way partitioning *---------------------------------------------------------------------*/ mcvwgt = idxsmalloc(2*(*nvtxs), 0, "METIS_PartGraphForContact: mcvwgt"); for (i=0; i<*nvtxs; i++) { mcvwgt[2*i+0] = 1; mcvwgt[2*i+1] = (sflag[i] == 0 ? 0 : 1); } adjwgt = idxmalloc(xadj[*nvtxs], "METIS_PartGraphForContact: adjwgt"); for (i=0; i<*nvtxs; i++) { for (j=xadj[i]; jdtree, leafpart, dtpart, &nclean, &naclean, &ndirty, &maxdepth, marker); mprintf("NNodes: %5D, NLNodes: %5D, NClean: %5D, NAClean: %5D, NDirty: %5D, MaxDepth: %3D\n", nnodes, nlnodes, nclean, naclean, ndirty, maxdepth); /*--------------------------------------------------------------------- * Create the tree-induced coarse graph and refine it *---------------------------------------------------------------------*/ cgraph = CreatePartitionGraphForContact(*nvtxs, xadj, adjncy, mcvwgt, adjwgt, nlnodes, leafpart); for (i=0; i<*nvtxs; i++) part[leafpart[i]] = dtpart[i]; ComputePartitionBalance(cgraph, *nparts, part, lbvec); mprintf(" %D-way Edge-Cut: %7D, Balance: %5.2f %5.2f\n", *nparts, ComputeCut(cgraph, part), lbvec[0], lbvec[1]); rwgtflag = 3; rnumflag = 0; METIS_mCRefineGraphKway(&(cgraph->nvtxs), &ncon, cgraph->xadj, cgraph->adjncy, cgraph->vwgt, cgraph->adjwgt, &rwgtflag, &rnumflag, nparts, rubvec, options, edgecut, part); ComputePartitionBalance(cgraph, *nparts, part, lbvec); mprintf(" %D-way Edge-Cut: %7D, Balance: %5.2f %5.2f\n", *nparts, ComputeCut(cgraph, part), lbvec[0], lbvec[1]); /*--------------------------------------------------------------------- * Use that to compute the partition of the original graph *---------------------------------------------------------------------*/ idxcopy(cgraph->nvtxs, part, dtpart); for (i=0; i<*nvtxs; i++) part[i] = dtpart[leafpart[i]]; ComputePartitionBalance(&graph, *nparts, part, lbvec); idxset(*nvtxs, 1, graph.vwgt); mprintf(" %D-way Edge-Cut: %7D, Volume: %7D, Balance: %5.2f %5.2f\n", *nparts, ComputeCut(&graph, part), ComputeVolume(&graph, part), lbvec[0], lbvec[1]); /*--------------------------------------------------------------------- * Induce the final decission tree *---------------------------------------------------------------------*/ nnodes = nlnodes = nclean = naclean = ndirty = maxdepth = 0; InduceDecissionTree(*nvtxs, xyzcand, sflag, *nparts, part, *nvtxs/((40)*(*nparts)), 1, 1.00, &nnodes, &nlnodes, cinfo->dtree, leafpart, dtpart, &nclean, &naclean, &ndirty, &maxdepth, marker); mprintf("NNodes: %5D, NLNodes: %5D, NClean: %5D, NAClean: %5D, NDirty: %5D, MaxDepth: %3D\n", nnodes, nlnodes, nclean, naclean, ndirty, maxdepth); /*--------------------------------------------------------------------- * Populate the remaining fields of the cinfo data structure *---------------------------------------------------------------------*/ cinfo->nnodes = nnodes; cinfo->nleafs = nlnodes; idxcopy(*nvtxs, part, cinfo->part); BuildDTLeafContents(cinfo, sflag); CheckDTree(*nvtxs, xyzcoords, part, cinfo); gk_free((void **)&mcvwgt, &dtpart, &xyzcand[0], &xyzcand[1], &xyzcand[2], &marker, &adjwgt, LTERM); if (*numflag == 1) Change2FNumbering(*nvtxs, xadj, adjncy, part); return (void *)cinfo; } /************************************************************************* * This function is the entry point for KMETIS **************************************************************************/ void METIS_UpdateContactInfo(void *raw_cinfo, idxtype *nvtxs, double *xyzcoords, idxtype *sflag) { idxtype i, root, nchanges; ContactInfoType *cinfo; DTreeNodeType *dtree; cinfo = (ContactInfoType *)raw_cinfo; dtree = cinfo->dtree; if (cinfo->nvtxs != *nvtxs) errexit("The provided number of vertices do not match the initial information: %d %d\n", *nvtxs, cinfo->nvtxs); /* Go and reset the nsvtxs fields of all the nodes */ for (i=0; innodes; i++) { dtree[i].nvtxs = 0; dtree[i].nsvtxs = 0; } /* Go and traverse each surface node and see where it gets assigned (We only focus on surface nodes. Right???) */ for (nchanges=0, i=0; i<*nvtxs; i++) { if (1 || sflag[i]) { for (root=0; dtree[root].leafid == -1;) root = (xyzcoords[3*i+dtree[root].dim] <= dtree[root].value ? dtree[root].left : dtree[root].right); if (cinfo->leafpart[i] != dtree[root].leafid && sflag[i]) nchanges++; cinfo->leafpart[i] = dtree[root].leafid; dtree[root].nvtxs++; if (sflag[i]) dtree[root].nsvtxs++; } } mprintf("NChanges: %D\n", nchanges); BuildDTLeafContents(cinfo, sflag); return; for (i=0; innodes; i++) { if (dtree[i].leafid != -1) mprintf("%4D %4D %4D %4D\n", dtree[i].nvtxs, dtree[i].nsvtxs, dtree[i].leafid, dtree[i].partid); } } /************************************************************************* * This function is the entry point for KMETIS **************************************************************************/ void *METIS_SetupContact0(idxtype *nvtxs, double *xyzcoords, idxtype *sflag, idxtype *nparts, idxtype *part) { idxtype i, j, ii, dim, ncontacts, wgtflag, mcnumflag, nnodes, nlnodes, nclean, naclean, ndirty, maxdepth, rwgtflag, rnumflag; idxtype *mcvwgt, *dtpart, *marker, *leafpart, *csflag, *cpart; idxtype *adjwgt; GraphType graph, *cgraph; ContactInfoType *cinfo; DKeyValueType *xyzcand[3]; /*--------------------------------------------------------------------- * Allocate memory for the contact info type *---------------------------------------------------------------------*/ cinfo = (ContactInfoType *)gk_malloc(sizeof(ContactInfoType), "METIS_PartGraphForContact: cinfo"); cinfo->leafptr = idxsmalloc(*nvtxs+1, 0, "METIS_PartGraphForContact: leafptr"); cinfo->leafind = idxsmalloc(*nvtxs, 0, "METIS_PartGraphForContact: leafind"); cinfo->leafwgt = idxsmalloc(*nvtxs, 0, "METIS_PartGraphForContact: leafwgt"); cinfo->part = idxsmalloc(*nvtxs, 0, "METIS_PartGraphForContact: part"); leafpart = cinfo->leafpart = idxmalloc(*nvtxs, "METIS_PartGraphForContact: leafpart"); cinfo->dtree = (DTreeNodeType *)gk_malloc(sizeof(DTreeNodeType)*(*nvtxs), "METIS_PartGraphForContact: cinfo->dtree"); cinfo->nvtxs = *nvtxs; /*--------------------------------------------------------------------- * Induce the decission tree *---------------------------------------------------------------------*/ dtpart = idxmalloc(*nvtxs, "METIS_PartGraphForContact: dtpart"); marker = idxsmalloc(*nvtxs, 0, "METIS_PartGraphForContact: marker"); for (dim=0; dim<3; dim++) xyzcand[dim] = (DKeyValueType *)gk_malloc(sizeof(DKeyValueType)*(*nvtxs), "METIS_PartGraphForContact: xyzcand[dim]"); for (ncontacts=0, i=0; i<*nvtxs; i++) { if (sflag[i]) { for (dim=0; dim<3; dim++) { xyzcand[dim][ncontacts].key = xyzcoords[3*i+dim]; xyzcand[dim][ncontacts].val = i; } ncontacts++; } } for (dim=0; dim<3; dim++) idkeysort(ncontacts, xyzcand[dim]); nnodes = nlnodes = nclean = naclean = ndirty = maxdepth = 0; InduceDecissionTree(ncontacts, xyzcand, sflag, *nparts, part, ncontacts, 1, 1.00, &nnodes, &nlnodes, cinfo->dtree, leafpart, dtpart, &nclean, &naclean, &ndirty, &maxdepth, marker); mprintf("NNodes: %5D, NLNodes: %5D, NClean: %5D, NAClean: %5D, NDirty: %5D, MaxDepth: %3D\n", nnodes, nlnodes, nclean, naclean, ndirty, maxdepth); /*--------------------------------------------------------------------- * Populate the remaining fields of the cinfo data structure *---------------------------------------------------------------------*/ cinfo->nnodes = nnodes; cinfo->nleafs = nlnodes; idxcopy(*nvtxs, part, cinfo->part); BuildDTLeafContents(cinfo, sflag); CheckDTreeSurface(*nvtxs, xyzcoords, part, cinfo, sflag); gk_free((void **)&dtpart, &xyzcand[0], &xyzcand[1], &xyzcand[2], &marker, LTERM); /* for (i=0; idtree[i].leafid, cinfo->dtree[i].nsvtxs); */ return (void *)cinfo; } /************************************************************************* * This function is the entry point for KMETIS **************************************************************************/ void *METIS_SetupContact(idxtype *nvtxs, double *xyzcoords, idxtype *sflag, idxtype *nparts, idxtype *part) { idxtype i, j, ii, dim, ncontacts, wgtflag, mcnumflag, nnodes, nlnodes, nclean, naclean, ndirty, maxdepth, rwgtflag, rnumflag; idxtype *mcvwgt, *dtpart, *marker, *leafpart, *csflag, *cpart; idxtype *adjwgt; GraphType graph, *cgraph; ContactInfoType *cinfo; DKeyValueType *xyzcand[3]; /*--------------------------------------------------------------------- * Allocate memory for the contact info type *---------------------------------------------------------------------*/ cinfo = (ContactInfoType *)gk_malloc(sizeof(ContactInfoType), "METIS_PartGraphForContact: cinfo"); cinfo->leafptr = idxsmalloc(*nvtxs+1, 0, "METIS_PartGraphForContact: leafptr"); cinfo->leafind = idxsmalloc(*nvtxs, 0, "METIS_PartGraphForContact: leafind"); cinfo->leafwgt = idxsmalloc(*nvtxs, 0, "METIS_PartGraphForContact: leafwgt"); cinfo->part = idxsmalloc(*nvtxs, 0, "METIS_PartGraphForContact: part"); leafpart = cinfo->leafpart = idxmalloc(*nvtxs, "METIS_PartGraphForContact: leafpart"); cinfo->dtree = (DTreeNodeType *)gk_malloc(sizeof(DTreeNodeType)*(*nvtxs), "METIS_PartGraphForContact: cinfo->dtree"); cinfo->nvtxs = *nvtxs; /*--------------------------------------------------------------------- * Induce the decission tree *---------------------------------------------------------------------*/ dtpart = idxmalloc(*nvtxs, "METIS_PartGraphForContact: dtpart"); marker = idxsmalloc(*nvtxs, 0, "METIS_PartGraphForContact: marker"); for (dim=0; dim<3; dim++) { xyzcand[dim] = (DKeyValueType *)gk_malloc(sizeof(DKeyValueType)*(*nvtxs), "METIS_PartGraphForContact: xyzcand[dim]"); for (i=0; i<*nvtxs; i++) { xyzcand[dim][i].key = xyzcoords[3*i+dim]; xyzcand[dim][i].val = i; } idkeysort(*nvtxs, xyzcand[dim]); } nnodes = nlnodes = nclean = naclean = ndirty = maxdepth = 0; InduceDecissionTree(*nvtxs, xyzcand, sflag, *nparts, part, *nvtxs, 1, 1.00, &nnodes, &nlnodes, cinfo->dtree, leafpart, dtpart, &nclean, &naclean, &ndirty, &maxdepth, marker); mprintf("NNodes: %5D, NLNodes: %5D, NClean: %5D, NAClean: %5D, NDirty: %5D, MaxDepth: %3D\n", nnodes, nlnodes, nclean, naclean, ndirty, maxdepth); /*--------------------------------------------------------------------- * Populate the remaining fields of the cinfo data structure *---------------------------------------------------------------------*/ cinfo->nnodes = nnodes; cinfo->nleafs = nlnodes; idxcopy(*nvtxs, part, cinfo->part); BuildDTLeafContents(cinfo, sflag); CheckDTree(*nvtxs, xyzcoords, part, cinfo); gk_free((void **)&dtpart, &xyzcand[0], &xyzcand[1], &xyzcand[2], &marker, LTERM); /* for (i=0; idtree[i].leafid, cinfo->dtree[i].nsvtxs); */ return (void *)cinfo; } /************************************************************************* * This function is the entry point for detecting contacts between * bounding boxes and surface nodes **************************************************************************/ void METIS_FindContacts(void *raw_cinfo, idxtype *nboxes, double *boxcoords, idxtype *nparts, idxtype **r_cntptr, idxtype **r_cntind) { idxtype i, ncnts, tncnts, maxtncnts; idxtype *cntptr, *cntind, *auxcntind, *stack, *marker; ContactInfoType *cinfo; cinfo = (ContactInfoType *)raw_cinfo; maxtncnts = 6*(*nboxes); cntptr = idxsmalloc(*nboxes+1, 0, "METIS_FindContacts: cntptr"); cntind = idxmalloc(maxtncnts, "METIS_FindContacts: cntind"); auxcntind = idxmalloc(*nparts, "METIS_FindContacts: auxcntind"); stack = idxmalloc(cinfo->nnodes, "METIS_FindContacts: stack"); marker = idxsmalloc(*nparts, 0, "METIS_FindContacts: marker"); /* Go through each box and determine its contacting partitions */ for (tncnts=0, i=0; i<*nboxes; i++) { ncnts = FindBoxContacts(cinfo, boxcoords+i*6, stack, auxcntind, marker); if (ncnts == 0) mprintf("CSearchError: Box has no contacts!\n"); if (ncnts + tncnts >= maxtncnts) { maxtncnts += (tncnts+ncnts)*(*nboxes-i)/i; if ((cntind = (idxtype *)realloc(cntind, maxtncnts*sizeof(idxtype))) == NULL) errexit("Realloc failed! of %d words!\n", maxtncnts); } cntptr[i] = ncnts; idxcopy(ncnts, auxcntind, cntind+tncnts); tncnts += ncnts; } MAKECSR(i, *nboxes, cntptr); *r_cntptr = cntptr; *r_cntind = cntind; gk_free((void **)&auxcntind, &stack, &marker, LTERM); } /************************************************************************* * This function is the entry point for KMETIS **************************************************************************/ void METIS_FreeContactInfo(void *raw_cinfo) { ContactInfoType *cinfo; cinfo = (ContactInfoType *)raw_cinfo; gk_free((void **)&(cinfo->leafptr), &(cinfo->leafind), &(cinfo->leafwgt), &(cinfo->part), &(cinfo->leafpart), &(cinfo->dtree), &cinfo, LTERM); } /****************************************************************************** * This function creates a coarse graph corresponding to the partitioning vector *******************************************************************************/ GraphType *CreatePartitionGraphForContact(idxtype nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, idxtype cnvtxs, idxtype *part) { idxtype i, ii, j, jj, k, cnedges; idxtype *cxadj, *cadjncy, *cvwgt, *cadjwgt; idxtype *ptr, *ind, *marker; GraphType *cgraph; ptr = idxsmalloc(cnvtxs+1, 0, "CreatePartitionGraph: ptr"); ind = idxmalloc(nvtxs, "CreatePartitionGraph: ind"); marker = idxsmalloc(cnvtxs, -1, "CreatePartitionGraph: marker"); cgraph = CreateGraph(); cgraph->ncon = 2; cgraph->nvtxs = cnvtxs; cxadj = cgraph->xadj = idxsmalloc(cnvtxs+1, 0, "CreatePartitionGraph: cxadj"); cadjncy = cgraph->adjncy = idxmalloc(xadj[nvtxs], "CreatePartitionGraph: cadjncy"); cvwgt = cgraph->vwgt = idxmalloc(2*cnvtxs, "CreatePartitionGraph: cvwgt"); cadjwgt = cgraph->adjwgt = idxmalloc(xadj[nvtxs], "CreatePartitionGraph: cadjwgt"); for (i=0; i 0 ? 1 : 0); //mprintf("LEAF3: %5D %5D Skipping small node!\n", nvtxs, k); *r_ndirty += nvtxs*k; isleaf = 1; } else if (nvtxs < maxnvtxs && tpwgts[pid] >= (int)(minfrac*nvtxs)) { /* Determine if mostly one class */ //mprintf("LEAF2: %5D %5D %4D Almost pure node!\n", nvtxs, tpwgts[idxargmax(nparts, tpwgts)], idxargmax(nparts, tpwgts)); *r_naclean += nvtxs; isleaf = 1; } else { /* Check if all coordinates are the same */ for (dim=0; dim<3; dim++) { for (i=1; i DEPSILON) break; } if (i != nvtxs) break; } if (dim == 3) { /* All coordinates matched! Treat it as a dirty node! */ for (k=0, i=0; i 0 ? 1 : 0); mprintf("LEAF4: %5D %5D Skipping same coord-nodes! (%D %D)\n", nvtxs, k, isclean, part[xyzcand[0][0].val]); *r_ndirty += nvtxs*k; isleaf = 1; } } if (isleaf) { for (i=0; i DEPSILON) { scores[dim] = sqrt(sum2[0])+sqrt(sum2[1]); points[dim] = (xyzcand[dim][i].key+xyzcand[dim][i+1].key)/2.0; lnvtxs[dim] = nleft; break; } } #ifdef PRINTSTAT if (i == nvtxs-1) mprintf("DTree: Initial Scan Along dim %D failed!\n", dim); #endif /* Continue with the rest */ for (i++; i= nvtxs/2) { if (fabs(xyzcand[dim][i].key - xyzcand[dim][i+1].key) < DEPSILON) continue; scores[dim] = xyzcand[dim][nvtxs-1].key - xyzcand[dim][0].key; /* Use the axis span as the score */ points[dim] = (xyzcand[dim][i].key+xyzcand[dim][i+1].key)/2.0; lnvtxs[dim] = nleft; break; } } else { if (newscore > scores[dim]) { if (fabs(xyzcand[dim][i].key - xyzcand[dim][i+1].key) < DEPSILON) continue; scores[dim] = newscore; points[dim] = (xyzcand[dim][i].key+xyzcand[dim][i+1].key)/2.0; lnvtxs[dim] = nleft; } } //mprintf("%5D %f %f %f\n", nleft, newscore, sum2[0], sum2[1]); } #ifdef PRINTSTAT /* Print some Stats */ if (scores[dim] >= 0) { mprintf("Dim: %3D, Score: %f, Point: %f [%5D %5D] [%f %f]\n", dim, scores[dim], points[dim], lnvtxs[dim], nvtxs-lnvtxs[dim], xyzcand[dim][0].key, xyzcand[dim][nvtxs-1].key); idxcopy(nparts, tpwgts, pwgts[1]); idxset(nparts, 0, pwgts[0]); for (i=0; i 0) mprintf("%5D => %5D %5D\n", j, pwgts[0][j], pwgts[1][j]); } #endif } /* Determine the best overall score */ bestdim = 0; bestscore = scores[0]; bestpoint = points[0]; for (dim=1; dim<3; dim++) { if (scores[dim] > bestscore) { bestscore = scores[dim]; bestpoint = points[dim]; bestdim = dim; } } if (bestscore <= 0.0) errexit("Major Failure... Non-seperable! %4d nodes. Needs to be fixed!\n", nvtxs); dtree[mynodeID].dim = bestdim; dtree[mynodeID].value = bestpoint; //mprintf("BestDim: %D!\n", bestdim); /*----------------------------------------------------------------------- * Ok, now go and do the split *-----------------------------------------------------------------------*/ nleft = lnvtxs[bestdim]; nright = nvtxs - nleft; for (dim=0; dim<3; dim++) { lxyzcand[dim] = (DKeyValueType *)gk_malloc(sizeof(DKeyValueType)*nleft, "InduceDecissionTree: lxyzcand[dim]"); rxyzcand[dim] = (DKeyValueType *)gk_malloc(sizeof(DKeyValueType)*nright, "InduceDecissionTree: rxyzcand[dim]"); } /* Mark the left vertices */ for (i=0; invtxs; nleafs = cinfo->nleafs; part = cinfo->part; leafpart = cinfo->leafpart; leafptr = cinfo->leafptr; leafind = cinfo->leafind; leafwgt = cinfo->leafwgt; cand = (KeyValueType *)gk_malloc(sizeof(KeyValueType)*nvtxs, "BuildDTLeafContents: cand"); for (ncontacts=0, i=0; i 1) { mprintf("%4D, ", i); for (j=leafptr[i]; j ", i); for (j=leafptr[i]; jleafptr; leafind = cinfo->leafind; dtree = cinfo->dtree; //mprintf("%e %e %e %e %e %e\n", coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); stack[0] = 0; k = 1; ncnts = 0; while (k > 0) { root = stack[--k]; /* See if you hit a leaf */ if ((leafid = dtree[root].leafid) != -1) { //mprintf("Got to a leaf.... %D %D %D\n", leafid, dtree[root].nsvtxs, leafptr[leafid+1]-leafptr[leafid]); if (dtree[root].nsvtxs > 0) { /* Add unique processor IDs. */ for (j=leafptr[leafid]; j ", dtree[root].dim, dtree[root].value, dtree[root].left, dtree[root].right); if (coords[dtree[root].dim] <= dtree[root].value) { /* min <= value */ stack[k++] = dtree[root].left; //mprintf(" %D", stack[k-1]); } if (coords[3+dtree[root].dim] >= dtree[root].value) { /* max >= value */ stack[k++] = dtree[root].right; //mprintf(" %D", stack[k-1]); } //mprintf("\n"); } for (i=0; ileafptr; leafind = cinfo->leafind; dtree = cinfo->dtree; for (i=0; ileafpart[i] != dtree[root].leafid) mprintf("DTError! %4D %4D %4D %4D %4D\n", i, cinfo->leafpart[i], dtree[root].leafid, part[i], leafind[leafptr[dtree[root].leafid]]); } } /*********************************************************************************** * This function checks the DT to see if it properly "classifies" all points ************************************************************************************/ void CheckDTreeSurface(idxtype nvtxs, double *xyzcoords, idxtype *part, ContactInfoType *cinfo, idxtype *sflag) { idxtype i, j, k, root; idxtype *leafptr, *leafind; DTreeNodeType *dtree; leafptr = cinfo->leafptr; leafind = cinfo->leafind; dtree = cinfo->dtree; for (i=0; ileafpart[i] != dtree[root].leafid) mprintf("SDTError! %4D %4D %4D %4D %4D\n", i, cinfo->leafpart[i], dtree[root].leafid, part[i], leafind[leafptr[dtree[root].leafid]]); } } /************************************************************************* * This function is the entry point for KMETIS **************************************************************************/ void *METIS_PartSurfForContactRCB(idxtype *nvtxs, double *xyzcoords, idxtype *sflag, idxtype *nparts, idxtype *part, idxtype *bestdims) { idxtype i, j, nsurf, dim, ncon, nnodes, nlnodes; idxtype *marker, *spart; ContactInfoType *cinfo; DKeyValueType *xyzcand[3]; double *myxyzcoords; /*--------------------------------------------------------------------- * Allocate memory for the contact info type *---------------------------------------------------------------------*/ cinfo = (ContactInfoType *)gk_malloc(sizeof(ContactInfoType), "METIS_PartGraphForContact: cinfo"); cinfo->leafptr = idxsmalloc(*nvtxs+1, 0, "METIS_PartGraphForContact: leafptr"); cinfo->leafind = idxsmalloc(*nvtxs, 0, "METIS_PartGraphForContact: leafind"); cinfo->leafwgt = idxsmalloc(*nvtxs, 0, "METIS_PartGraphForContact: leafwgt"); cinfo->part = idxsmalloc(*nvtxs, 0, "METIS_PartGraphForContact: part"); cinfo->leafpart = idxmalloc(*nvtxs, "METIS_PartGraphForContact: leafpart"); cinfo->dtree = (DTreeNodeType *)gk_malloc(sizeof(DTreeNodeType)*(*nvtxs), "METIS_PartGraphForContact: cinfo->dtree"); /*--------------------------------------------------------------------- * Induce the decission tree *---------------------------------------------------------------------*/ myxyzcoords = gk_dmalloc(3*(*nvtxs), "METIS_PartSurfForContactRCB: myxyzcoords"); marker = idxsmalloc(*nvtxs, 0, "METIS_PartGraphForContact: marker"); for (dim=0; dim<3; dim++) { xyzcand[dim] = (DKeyValueType *)gk_malloc(sizeof(DKeyValueType)*(*nvtxs), "METIS_PartGraphForContact: xyzcand[dim]"); for (nsurf=0, i=0; i<*nvtxs; i++) { if (sflag[i]) { myxyzcoords[3*nsurf+dim] = xyzcoords[3*i+dim]; xyzcand[dim][nsurf].key = xyzcoords[3*i+dim]; xyzcand[dim][nsurf].val = nsurf++; } } idkeysort(nsurf, xyzcand[dim]); } spart = idxsmalloc(nsurf, 0, "METIS_PartGraphForContact: spart"); nnodes = nlnodes = 0; InduceRCBTree(nsurf, xyzcand, 0, *nparts, &nnodes, &nlnodes, cinfo->dtree, cinfo->leafpart, spart, marker, bestdims); mprintf("NNodes: %5D, NLNodes: %5D\n", nnodes, nlnodes); /* Project the partition back to the original space */ for (nsurf=0, i=0; i<*nvtxs; i++) part[i] = (sflag[i] ? spart[nsurf++] : -1); /*--------------------------------------------------------------------- * Populate the remaining fields of the cinfo data structure *---------------------------------------------------------------------*/ cinfo->nvtxs = nsurf; cinfo->nnodes = nnodes; cinfo->nleafs = nlnodes; idxcopy(nsurf, spart, cinfo->part); idxset(nsurf, 1, marker); BuildDTLeafContents(cinfo, marker); CheckDTree(nsurf, myxyzcoords, spart, cinfo); gk_free((void **)&xyzcand[0], &xyzcand[1], &xyzcand[2], &myxyzcoords, &marker, &spart, LTERM); for (i=0; innodes; i++) bestdims[i] = cinfo->dtree[i].dim; return (void *)cinfo; } /************************************************************************* * This function induces a DT that satisfied the given size requirements **************************************************************************/ idxtype InduceRCBTree(idxtype nvtxs, DKeyValueType **xyzcand, idxtype firstPID, idxtype nparts, idxtype *r_nnodes, idxtype *r_nlnodes, DTreeNodeType *dtree, idxtype *leafpart, idxtype *part, idxtype *marker, idxtype *oldBestDims) { idxtype i, nr, nl, j, k, mynodeID, dim, bestdim, lnvtxs, rnvtxs, lnparts, rnparts; DKeyValueType *lxyzcand[3], *rxyzcand[3]; double bestpoint; mynodeID = (*r_nnodes)++; dtree[mynodeID].nvtxs = nvtxs; dtree[mynodeID].nsvtxs = nvtxs; dtree[mynodeID].leafid = -1; /*----------------------------------------------------------------------- * Check the exit conditions *-----------------------------------------------------------------------*/ if (nparts == 1) { //mprintf("Pid:%D, Size:%D\n", firstPID, nvtxs); for (i=0; i DEPSILON) break; } lnvtxs++; rnvtxs = nvtxs - lnvtxs; } if (rnvtxs <= 0) { if (bestdim != -1) mprintf("Finding a dimension for %D points...\n", nvtxs); lnparts = nparts/2; rnparts = nparts - lnparts; lnvtxs = nvtxs*lnparts/nparts; for (bestdim=0, i=1; i<3; i++) bestdim = (xyzcand[i][nvtxs-1].key - xyzcand[i][0].key > xyzcand[bestdim][nvtxs-1].key - xyzcand[bestdim][0].key ? i : bestdim); for (; lnvtxs DEPSILON) break; } lnvtxs++; rnvtxs = nvtxs - lnvtxs; } dtree[mynodeID].dim = bestdim; dtree[mynodeID].value = bestpoint = (xyzcand[bestdim][lnvtxs-1].key+xyzcand[bestdim][lnvtxs].key)/2; /* Print some Stats */ //mprintf("Dim: %3D, Point: %f [%5D %5D] [%3D %3D]\n", bestdim, bestpoint, lnvtxs, rnvtxs, lnparts, rnparts); /*----------------------------------------------------------------------- * Ok, now go and do the split *-----------------------------------------------------------------------*/ for (dim=0; dim<3; dim++) { lxyzcand[dim] = (DKeyValueType *)gk_malloc(sizeof(DKeyValueType)*lnvtxs, "InduceDecissionTree: lxyzcand[dim]"); rxyzcand[dim] = (DKeyValueType *)gk_malloc(sizeof(DKeyValueType)*rnvtxs, "InduceDecissionTree: rxyzcand[dim]"); } /* Mark the left vertices */ for (i=0; i