/*static void p1bucket();*/ private static void pbuckets(bilist ****buckets, /* pointers to bucket lists */ bilist **listspace, /* elements within buckets */ int maxdeg, /* maximum degree of a vertex */ int nsets /* number of sets being divided into */ ) { bilist *lptr; /* points to correct listspace */ int i, j; /* loop counter */ Console.WriteLine(); for (i = 0; i < nsets; i++) { for (j = 0; j < nsets; j++) { if (i != j) { Console.WriteLine("For transition {0:d} -> {1:d}", i, j); if (j > i) { lptr = listspace[j - 1]; } else { lptr = listspace[j]; } p1bucket(buckets[i][j], lptr, maxdeg); Console.WriteLine(); } } } Console.WriteLine(); }
static void free_kl( /* Free everything malloc'd for KL. */ bilist ****buckets, /* space for bucket sorts */ bilist **listspace, /* space for all bidirectional elements */ int **dvals, /* change in penalty for each possible move */ int **tops /* starting dval for each type of move */ ) { Marshal.FreeHGlobal((IntPtr)dvals); Marshal.FreeHGlobal((IntPtr)tops); Marshal.FreeHGlobal((IntPtr)listspace[0]); Marshal.FreeHGlobal((IntPtr)buckets[0][1]); Marshal.FreeHGlobal((IntPtr)listspace); Marshal.FreeHGlobal((IntPtr)buckets); }
/* Idea: * 'buckets[i][j]' is a set of buckets to sort moves from i to j. * listspace[i] is space for lists in buckets[i][j]. * Loop through all nonequal pairs [i][j], taking the first element * in each list. Compare them all to find the largest allowed move. * Make that move, and save it in movelist. */ public static void bucketsort1(vtx_data **graph, /* graph data structure */ int vtx, /* vertex being added to lists */ bilist ****buckets, /* array of lists for bucket sort */ bilist **listspace, /* list data structure for each vertex */ int **dvals, /* d-values for each vertex for removing */ int *sets, /* processor each vertex is assigned to */ float *[] term_wgts, /* weights for terminal propagation */ int maxdval, /* maximum possible dvalue for a vertex */ int nsets, /* number of sets being divided into */ int [][] hops, /* hop cost between sets */ bool useEdgeWeights /* are edge weights being used? */ ) { bilist *lptr = null; /* pointer to an element in listspace */ float * ewptr = null; /* loops through edge weights */ int * edges = null; /* edge list for a vertex */ int myset; /* set that current vertex belongs to */ int newset; /* set current vertex could move to */ int set; /* set that neighboring vertex belongs to */ int weight; /* edge weight for a particular edge */ float tval; /* terminal propagation value */ int val; /* terminal propagation rounded value */ double cut_cost; /* relative cut/hop importance */ double hop_cost; /* relative hop/cut importance */ int myhop; /* hops associated with current vertex */ int j, l; /* loop counters */ /* Compute d-vals by seeing which sets neighbors belong to. */ cut_cost = hop_cost = 1; if (term_wgts[1] != null) { if (CUT_TO_HOP_COST > 1) { cut_cost = CUT_TO_HOP_COST; } else { hop_cost = 1.0 / CUT_TO_HOP_COST; } } weight = (int)(cut_cost + .5); myset = sets[vtx]; /* Initialize all the preference values. */ if (term_wgts[1] != null) { /* Using terminal propagation. */ if (myset == 0) /* No terminal value. */ { for (newset = 1; newset < nsets; newset++) { tval = (term_wgts[newset])[vtx]; if (tval < 0) { val = (int)(-tval * hop_cost + .5); val = -val; } else { val = (int)(tval * hop_cost + .5); } dvals[vtx][newset - 1] = val; } } else { tval = -(term_wgts[myset])[vtx]; if (tval < 0) { val = (int)(-tval * hop_cost + .5); val = -val; } else { val = (int)(tval * hop_cost + .5); } dvals[vtx][0] = val; l = 1; for (newset = 1; newset < nsets; newset++) { if (newset != myset) { tval = (term_wgts[newset])[vtx] - (term_wgts[myset])[vtx]; if (tval < 0) { val = (int)(-tval * hop_cost + .5); val = -val; } else { val = (int)(tval * hop_cost + .5); } dvals[vtx][l] = val; l++; } } } } else { for (j = 0; j < nsets - 1; j++) { dvals[vtx][j] = 0; } } /* First count the neighbors in each set. */ edges = graph[vtx]->edges; if (useEdgeWeights) { ewptr = graph[vtx]->ewgts; } for (j = graph[vtx]->nedges - 1; j != 0; j--) { set = sets[*(++edges)]; if (set < 0) { set = -set - 1; } if (useEdgeWeights) { weight = (int)(*(++ewptr) * cut_cost + .5); } myhop = hops[myset][set]; l = 0; for (newset = 0; newset < nsets; newset++) { if (newset != myset) { dvals[vtx][l] += weight * (myhop - hops[newset][set]); l++; } } } /* Now add to appropriate buckets. */ l = 0; for (newset = 0; newset < nsets; newset++) { if (newset != myset) { lptr = listspace[l]; add2bilist(&lptr[vtx], &buckets[myset][newset][dvals[vtx][l] + maxdval]); ++l; } } }
/* Idea: * 'buckets[i][j]' is a set of buckets to sort moves from i to j. * listspace[i] is space for lists in buckets[i][j]. * Loop through all nonequal pairs [i][j], taking the first element * in each list. Compare them all to find the largest allowed move. * Make that move, and save it in movelist. */ /* Routine slightly streamlined for case with only two sets. */ public static void bucketsorts_bi(vtx_data **graph, /* graph data structure */ int nvtxs, /* number of vertices */ bilist ****buckets, /* array of lists for bucket sort */ bilist **listspace, /* list data structure for each vertex */ int **dvals, /* d-values for each vertex for removing */ int *sets, /* processor each vertex is assigned to */ float *[] term_wgts, /* weights for terminal propagation */ int maxdval, /* maximum possible dvalue for a vertex */ int nsets, /* number of sets being divided into */ bool parity, /* work in forward or backward direction? */ int [][] hops, /* hop cost between sets */ int *bspace, /* indices for randomly ordering vtxs */ int list_length, /* number of values in bspace to work with */ int npass, /* which pass through KL is this? */ bool useEdgeWeights /* are edge weights being used? */ ) { bilist **bptr = null; /* loops through set of buckets */ bilist * lptr = null; /* pointer to an element in listspace */ float * ewptr = null; /* loops through edge weights */ float * twptr = null; /* weights for terminal propagation */ int * bsptr = null; /* loops through bspace */ int * edges = null; /* edge list for a vertex */ int myset; /* set current vertex belongs to */ int other_set; /* set current vertex doesn't belong to */ int set; /* set that neighboring vertex belongs to */ int weight; /* edge weight for a particular edge */ int vtx; /* vertex in graph */ int val; /* terminal propagation rounded value */ double cut_cost; /* relative cut/hop importance */ double hop_cost; /* relative hop/cut importance */ int myhop; /* hops associated with current vertex */ int i, j; /* loop counters */ /* For each vertex, compute d-values for each possible transition. */ /* Then store them in each appropriate bucket. */ if (npass == 1 || !KL_UNDO_LIST || list_length == nvtxs) { /* Empty all the buckets. */ /* Last clause catches case where lists weren't undone. */ bptr = buckets[0][1]; for (i = nsets * (nsets - 1) * (2 * maxdval + 1); i != 0; i--) { *bptr++ = null; } } /* Randomize the order of the vertices */ if ((KL_UNDO_LIST && list_length == nvtxs) || !KL_UNDO_LIST) { list_length = nvtxs; bsptr = bspace; if (parity) { for (i = 1; i <= nvtxs; i++) { *bsptr++ = i; } } else { for (i = nvtxs; i != 0; i--) { *bsptr++ = i; } } } if (KL_RANDOM) { randomize(bspace - 1, list_length); } /* Now compute d-vals by seeing which sets neighbors belong to. */ cut_cost = hop_cost = 1; if (term_wgts[1] != null) { if (CUT_TO_HOP_COST > 1) { cut_cost = CUT_TO_HOP_COST; } else { hop_cost = 1.0 / CUT_TO_HOP_COST; } } weight = (int)(cut_cost + .5); bsptr = bspace; twptr = term_wgts[1]; for (i = 0; i < list_length; i++) /* Loop through vertices. */ { vtx = *bsptr++; myset = sets[vtx]; other_set = myset == 0 ? 1 : 0; /* Initialize all the preference values. */ if (twptr != null) { /* Using terminal propagation. Round to integer value. */ if (twptr[vtx] < 0) { val = (int)(-twptr[vtx] * hop_cost + .5); val = -val; } else { val = (int)(twptr[vtx] * hop_cost + .5); } if (myset == 0) { dvals[vtx][0] = val; } else { dvals[vtx][0] = -val; } } else { dvals[vtx][0] = 0; } /* First count the neighbors in each set. */ edges = graph[vtx]->edges; if (useEdgeWeights) { ewptr = graph[vtx]->ewgts; } for (j = graph[vtx]->nedges - 1; j != 0; j--) { set = sets[*(++edges)]; if (set < 0) { set = -set - 1; } if (useEdgeWeights) { weight = (int)((*(++ewptr)) * cut_cost + .5); } myhop = hops[myset][set]; dvals[vtx][0] += weight * (myhop - hops[other_set][set]); } /* Now add to appropriate buckets. */ lptr = listspace[0]; add2bilist(&lptr[vtx], &buckets[myset][other_set][dvals[vtx][0] + maxdval]); } }
public static void make_bndy_list(vtx_data **graph, /* data structure for graph */ bilist *movelist, /* list of vtxs to be moved */ bilist ****buckets, /* array of lists for bucket sort */ bilist **listspace, /* list data structure for each vertex */ int *sets, /* processor each vertex is assigned to */ int nsets, /* number of sets divided into */ int *bspace, /* list of active vertices for bucketsort */ int **tops, /* top of each set of buckets */ int **bndy_list /* list of boundary vertices returned */ ) { bilist *bptr; /* loops through bspace */ int vtx; /* vertex that was moved */ int set; /* set a vertex is in */ int list_length; /* number of active vertices */ int bndy_length; /* number of vertices actually on boundary */ int size; /* array spacing */ int i, j, k; /* loop counters */ /* First push all the moved vertices onto list, so they can be flagged. */ /* They've already been removed from buckets, so want to avoid them. */ size = (int)(&(listspace[0][1]) - &(listspace[0][0])); bptr = movelist; list_length = 0; while (bptr != null) { vtx = ((int)(bptr - listspace[0])) / size; bspace[list_length++] = vtx; bptr = bptr->next; } /* Now get all the vertices still in the bucket lists. */ for (k = tops[0][1]; k >= 0; k--) { bptr = buckets[0][1][k]; while (bptr != null) { vtx = ((int)(bptr - listspace[0])) / size; bspace[list_length++] = vtx; bptr = bptr->next; } } for (i = 1; i < nsets; i++) { for (k = tops[i][0]; k >= 0; k--) { bptr = buckets[i][0][k]; while (bptr != null) { vtx = ((int)(bptr - listspace[0])) / size; bspace[list_length++] = vtx; bptr = bptr->next; } } } /* Now that list is constructed, go reconstruct all the set numbers. */ bndy_length = 0; for (i = 0; i < list_length; i++) { vtx = bspace[i]; set = sets[vtx]; for (j = 1; j < graph[vtx]->nedges; j++) { if (sets[graph[vtx]->edges[j]] != set) { bspace[bndy_length++] = vtx; break; } } } /* Finally, copy boundary vertices into boundary list. */ *bndy_list = (int *)Marshal.AllocHGlobal((bndy_length + 1) * sizeof(int)); for (i = 0; i < bndy_length; i++) { (*bndy_list)[i] = bspace[i]; } (*bndy_list)[bndy_length] = 0; }
private static int make_kl_list(vtx_data **graph, /* data structure for graph */ bilist *movelist, /* list of vtxs to be moved */ bilist ****buckets, /* array of lists for bucket sort */ bilist **listspace, /* list data structure for each vertex */ int *sets, /* processor each vertex is assigned to */ int nsets, /* number of sets divided into */ int *bspace, /* list of active vertices for bucketsort */ int **dvals, /* d-values for each transition */ int maxdval /* maximum d-value for a vertex */ ) { bilist **list; /* bucket to erase element from */ bilist * vptr; /* loops through movelist */ int * bptr; /* loops through bspace */ int * iptr; /* loops through edge list */ int vtx; /* vertex that was moved */ int neighbor; /* neighbor of a vertex */ int myset; /* set a vertex is in */ int newset; /* loops through other sets */ int list_length; /* number of values put in bspace */ int size; /* array spacing */ int i, l; /* loop counter */ /* First push all the moved vertices onto list, so they can be flagged. */ /* They've already been removed from buckets, so want to avoid them. */ size = (int)(&(listspace[0][1]) - &(listspace[0][0])); vptr = movelist; bptr = bspace; list_length = 0; while (vptr != null) { vtx = ((int)(vptr - listspace[0])) / size; *bptr++ = vtx; if (sets[vtx] >= 0) { sets[vtx] = -sets[vtx] - 1; } ++list_length; vptr = vptr->next; } /* Now look at all the neighbors of moved vertices. */ vptr = movelist; while (vptr != null) { vtx = ((int)(vptr - listspace[0])) / size; iptr = graph[vtx]->edges; for (i = graph[vtx]->nedges - 1; i != 0; i--) { neighbor = *(++iptr); if (sets[neighbor] >= 0) { *bptr++ = neighbor; ++list_length; myset = sets[neighbor]; sets[neighbor] = -sets[neighbor] - 1; /* Remove neighbor entry from all his buckets. */ /* Note: vertices in movelist already removed from buckets. */ l = 0; for (newset = 0; newset < nsets; newset++) { if (newset != myset) { list = &buckets[myset][newset][dvals[neighbor][l] + maxdval]; removebilist(&listspace[l][neighbor], list); l++; } } } } vptr = vptr->next; } /* Now that list is constructed, go reconstruct all the set numbers. */ bptr = bspace; for (i = list_length; i != 0; i--) { vtx = *bptr++; sets[vtx] = -sets[vtx] - 1; } return(list_length); }
/* Idea: * 'buckets[i][j]' is a set of buckets to sort moves from i to j. * listspace[i] is space for lists in buckets[i][j]. * Loop through all nonequal pairs [i][j], taking the first element * in each list. Compare them all to find the largest allowed move. * Make that move, and save it in movelist. */ public static bool nway_kl(vtx_data **graph, /* data structure for graph */ int nvtxs, /* number of vtxs in graph */ bilist ****buckets, /* array of lists for bucket sort */ bilist **listspace, /* list data structure for each vertex */ int **tops, /* 2-D array of top of each set of buckets */ int **dvals, /* d-values for each transition */ int *sets, /* processor each vertex is assigned to */ int maxdval, /* maximum d-value for a vertex */ int nsets, /* number of sets divided into */ double [] goal, /* desired set sizes */ float *[] term_wgts, /* weights for terminal propagation */ int [][] hops, /* cost of set transitions */ int max_dev, /* largest allowed deviation from balance */ bool useEdgeWeights, /* are edge weights being used? */ int **bndy_list, /* list of vertices on boundary (0 ends) */ double [] startweight /* sum of vweights in each set (in and out) */ ) /* Suaris and Kedem algorithm for quadrisection, generalized to an */ /* arbitrary number of sets, with intra-set cost function specified by hops. */ /* Note: this is for a single divide step. */ /* Also, sets contains an initial (possibly crummy) partitioning. */ { bilist * movelist; /* list of vtxs to be moved */ bilist **endlist; /* end of movelists */ bilist * bestptr; /* best vertex in linked list */ bilist * bptr; /* loops through bucket list */ float * ewptr = null; /* loops through edge weights */ double * locked = null; /* weight of vertices locked in a set */ double * loose = null; /* weight of vtxs that can move from a set */ int * bspace = null; /* list of active vertices for bucketsort */ double * weightsum = null; /* sum of vweights for each partition */ int * edges = null; /* edge list for a vertex */ int * bdy_ptr = null; /* loops through bndy_list */ double time; /* timing parameter */ double delta; /* desire of sets to change size */ double bestdelta = -1; /* strongest delta value */ double deltaplus; /* largest negative deviation from goal size */ double deltaminus; /* largest negative deviation from goal size */ int list_length; /* how long is list of vertices to bucketsort? */ bool balanced; /* is partition balanced? */ bool temp_balanced; /* is intermediate partition balanced? */ bool ever_balanced; /* has any partition been balanced? */ int bestvtx = -1; /* best vertex to move */ int bestval = -1; /* best change in value for a vtx move */ int bestfrom = -1, bestto = -1; /* sets best vertex moves between */ int vweight; /* weight of best vertex */ int gtotal; /* sum of changes from moving */ int improved; /* total improvement from KL */ double balance_val = 0.0; /* how imbalanced is it */ double balance_best; /* best balance yet if trying hard */ double bestg; /* maximum gtotal found in KL loop */ double bestg_min; /* smaller than any possible bestg */ int beststep; /* step where maximum value occurred */ int neighbor; /* neighbor of a vertex */ int step_cutoff; /* number of negative steps in a row allowed */ int cost_cutoff; /* amount of negative d-values allowed */ int neg_steps; /* number of negative steps in a row */ int neg_cost; /* decrease in sum of d-values */ int vtx; /* vertex number */ int dval; /* dval of a vertex */ int group; /* set that a vertex is assigned to */ double cut_cost; /* if term_prop; relative cut/hop importance */ int diff; /* change in a d-value */ int stuck1st, stuck2nd; /* how soon will moves be disallowed? */ int beststuck1 = -1, beststuck2 = -1; /* best stuck values for tie-breaking */ int eweight; /* a particular edge weight */ bool worth_undoing; /* is it worth undoing list? */ float undo_frac; /* fraction of vtxs indicating worth of undoing */ int step; /* loops through movements of vertices */ bool parity; /* sort forwards or backwards? */ bool done; /* has termination criteria been achieved? */ int nbad; /* number of unhelpful passes in a row */ int npass; /* total number of passes */ int nbadtries; /* number of unhelpful passes before quitting */ bool enforce_balance; /* force a balanced partition? */ bool enforce_balance_hard; /* really force a balanced partition? */ bool balance_trouble; /* even balance_hard isn't working */ int size; /* array spacing */ int i, j, k, l; /* loop counters */ nbadtries = KL_NTRIES_BAD; enforce_balance = false; temp_balanced = false; enforce_balance_hard = false; balance_trouble = false; size = (int)(&(listspace[0][1]) - &(listspace[0][0])); undo_frac = 0.3f; cut_cost = 1; if (term_wgts[1] != null) { if (CUT_TO_HOP_COST > 1) { cut_cost = CUT_TO_HOP_COST; } } bspace = (int *)Marshal.AllocHGlobal(nvtxs * sizeof(int)); weightsum = (double *)Marshal.AllocHGlobal(nsets * sizeof(double)); locked = (double *)Marshal.AllocHGlobal(nsets * sizeof(double)); loose = (double *)Marshal.AllocHGlobal(nsets * sizeof(double)); if (bspace == null || weightsum == null || locked == null || loose == null) { Marshal.FreeHGlobal((IntPtr)loose); Marshal.FreeHGlobal((IntPtr)locked); Marshal.FreeHGlobal((IntPtr)weightsum); Marshal.FreeHGlobal((IntPtr)bspace); return(true); } if (*bndy_list != null) { bdy_ptr = *bndy_list; list_length = 0; while (*bdy_ptr != 0) { bspace[list_length++] = *bdy_ptr++; } Marshal.FreeHGlobal((IntPtr)(*bndy_list)); if (list_length == 0) /* No boundary -> make everybody bndy. */ { for (i = 0; i < nvtxs; i++) { bspace[i] = i + 1; } list_length = nvtxs; } /* Set dvals to flag uninitialized vertices. */ for (i = 1; i <= nvtxs; i++) { dvals[i][0] = 3 * maxdval; } } else { list_length = nvtxs; } step_cutoff = KL_BAD_MOVES; cost_cutoff = maxdval * step_cutoff / 7; if (cost_cutoff < step_cutoff) { cost_cutoff = step_cutoff; } deltaminus = deltaplus = 0; for (i = 0; i < nsets; i++) { if (startweight[i] - goal[i] > deltaplus) { deltaplus = startweight[i] - goal[i]; } else if (goal[i] - startweight[i] > deltaminus) { deltaminus = goal[i] - startweight[i]; } } balanced = (deltaplus + deltaminus <= max_dev); bestg_min = -2.0 * nvtxs * maxdval; parity = false; eweight = (int)(cut_cost + .5); nbad = 0; npass = 0; improved = 0; done = false; while (!done) { npass++; ever_balanced = false; /* Initialize various quantities. */ balance_best = 0; for (i = 0; i < nsets; i++) { for (j = 0; j < nsets; j++) { tops[i][j] = 2 * maxdval; } weightsum[i] = startweight[i]; loose[i] = weightsum[i]; locked[i] = 0; balance_best += goal[i]; } gtotal = 0; bestg = bestg_min; beststep = -1; movelist = null; endlist = &movelist; neg_steps = 0; /* Compute the initial d-values, and bucket-sort them. */ time = seconds(); if (nsets == 2) { bucketsorts_bi(graph, nvtxs, buckets, listspace, dvals, sets, term_wgts, maxdval, nsets, parity, hops, bspace, list_length, npass, useEdgeWeights); } else { bucketsorts(graph, nvtxs, buckets, listspace, dvals, sets, term_wgts, maxdval, nsets, parity, hops, bspace, list_length, npass, useEdgeWeights); } parity = !parity; kl_bucket_time += seconds() - time; if (DEBUG_KL == DebugFlagKL.PrintBucket) { pbuckets(buckets, listspace, maxdval, nsets); } /* Now determine the set of K-L moves. */ for (step = 1;; step++) { /* Find the highest d-value in each set. */ /* But only consider moves from large to small sets, or moves */ /* in which balance is preserved. */ /* Break ties in some nonarbitrary manner. */ bestval = -maxdval - 1; for (i = 0; i < nsets; i++) { for (j = 0; j < nsets; j++) { /* Only allow moves from large sets to small sets, or */ /* moves which preserve balance. */ if (i != j) { /* Find the best move from i to j. */ for (k = tops[i][j]; k >= 0 && buckets[i][j][k] == null; k--) { ; } tops[i][j] = k; if (k >= 0) { l = (j > i) ? j - 1 : j; vtx = ((int)(buckets[i][j][k] - listspace[l])) / size; vweight = graph[vtx]->vwgt; if ((enforce_balance_hard && weightsum[i] >= goal[i] && weightsum[j] <= goal[j] && weightsum[i] - goal[i] - (weightsum[j] - goal[j]) > max_dev) || (!enforce_balance_hard && weightsum[i] >= goal[i] && weightsum[j] <= goal[j]) || (!enforce_balance_hard && weightsum[i] - vweight - goal[i] > -(double)((max_dev + 1) / 2) && weightsum[j] + vweight - goal[j] < (double)((max_dev + 1) / 2))) { /* Is it the best move seen so far? */ if (k - maxdval > bestval) { bestval = k - maxdval; bestvtx = vtx; bestto = j; /* DO I NEED ALL THIS DATA? Just to break ties. */ bestdelta = Math.Abs(weightsum[i] - vweight - goal[i]) + Math.Abs(weightsum[j] + vweight - goal[j]); beststuck1 = (int)Math.Min(loose[i], goal[j] - locked[j]); beststuck2 = (int)Math.Max(loose[i], goal[j] - locked[j]); } else if (k - maxdval == bestval) { /* Tied. Is better balanced than current best? */ /* If tied, move among sets with most freedom. */ stuck1st = (int)Math.Min(loose[i], goal[j] - locked[j]); stuck2nd = (int)Math.Max(loose[i], goal[j] - locked[j]); delta = Math.Abs(weightsum[i] - vweight - goal[i]) + Math.Abs(weightsum[j] + vweight - goal[j]); /* NOTE: Randomization in this check isn't ideal */ /* if more than two guys are tied. */ if (delta < bestdelta || (delta == bestdelta && (stuck1st > beststuck1 || (stuck1st == beststuck1 && (stuck2nd > beststuck2 || (stuck2nd == beststuck2 && (KL_RANDOM && drandom() < .5))))))) { bestval = k - maxdval; bestvtx = vtx; bestto = j; bestdelta = delta; beststuck1 = stuck1st; beststuck2 = stuck2nd; } } } } } } } if (bestval == -maxdval - 1) /* No allowed moves */ { if (DEBUG_KL != DebugFlagKL.NoDebugging) { Console.WriteLine("No KL moves at step {0:d}. bestg = {1:g} at step {2:d}.\n", step, bestg, beststep); } break; } bestptr = &(listspace[0][bestvtx]); bestfrom = sets[bestvtx]; vweight = graph[bestvtx]->vwgt; weightsum[bestto] += vweight; weightsum[bestfrom] -= vweight; loose[bestfrom] -= vweight; locked[bestto] += vweight; if (enforce_balance) /* Check if this partition is balanced. */ { deltaminus = deltaplus = 0; for (i = 0; i < nsets; i++) { if (weightsum[i] - goal[i] > deltaplus) { deltaplus = weightsum[i] - goal[i]; } else if (goal[i] - weightsum[i] > deltaminus) { deltaminus = goal[i] - weightsum[i]; } } balance_val = deltaminus + deltaplus; temp_balanced = (balance_val <= max_dev); ever_balanced = (ever_balanced || temp_balanced); } gtotal += bestval; if (((gtotal > bestg && (!enforce_balance || temp_balanced)) || (enforce_balance_hard && balance_val < balance_best)) && step != nvtxs) { bestg = gtotal; beststep = step; if (enforce_balance_hard) { balance_best = balance_val; } if (temp_balanced) { enforce_balance_hard = false; } } if (DEBUG_KL == DebugFlagKL.MoreInfo || DEBUG_KL == DebugFlagKL.PrintBucket) { Console.WriteLine("At KL step {0:d}, bestvtx={1:d}, bestval={2:d} ({3:d}-> {4:d})", step, bestvtx, bestval, bestfrom, bestto); } /* Monitor the stopping criteria. */ if (bestval < 0) { if (!enforce_balance || ever_balanced) { neg_steps++; } if (bestg != bestg_min) { neg_cost = (int)(bestg - gtotal); } else { neg_cost = -maxdval - 1; } if ((neg_steps > step_cutoff || neg_cost > cost_cutoff) && !(enforce_balance && bestg == bestg_min) && (beststep != step)) { if (DEBUG_KL != DebugFlagKL.NoDebugging) { if (neg_steps > step_cutoff) { Console.WriteLine("KL step cutoff at step {0:d}. bestg = {1:g} at step {2:d}.", step, bestg, beststep); } else if (neg_cost > cost_cutoff) { Console.WriteLine("KL cost cutoff at step {0:d}. bestg = {1:g} at step {2:d}.", step, bestg, beststep); } } break; } } else if (bestval > 0) { neg_steps = 0; } /* Remove vertex from its buckets, and flag it as finished. */ l = 0; for (k = 0; k < nsets; k++) { if (k != bestfrom) { dval = dvals[bestvtx][l] + maxdval; removebilist(&listspace[l][bestvtx], &buckets[bestfrom][k][dval]); l++; } } /* Is there a better way to do this? */ sets[bestvtx] = -sets[bestvtx] - 1; /* Set up the linked list of moved vertices. */ bestptr->next = null; bestptr->prev = (bilist *)(ulong)bestto; *endlist = bestptr; endlist = &(bestptr->next); /* Now update the d-values of all the neighbors */ edges = graph[bestvtx]->edges; if (useEdgeWeights) { ewptr = graph[bestvtx]->ewgts; } for (j = graph[bestvtx]->nedges - 1; j != 0; j--) { neighbor = *(++edges); if (useEdgeWeights) { eweight = (int)(*(++ewptr) * cut_cost + .5); } /* First make sure neighbor is alive. */ if (sets[neighbor] >= 0) { group = sets[neighbor]; if (dvals[neighbor][0] >= 3 * maxdval) { /* New vertex, not yet in buckets. */ /* Can't be neighbor of moved vtx, so compute */ /* initial dvals and buckets, then update. */ bucketsort1(graph, neighbor, buckets, listspace, dvals, sets, term_wgts, maxdval, nsets, hops, useEdgeWeights); } l = 0; for (k = 0; k < nsets; k++) { if (k != group) { diff = eweight * (hops[k][bestfrom] - hops[group][bestfrom] + hops[group][bestto] - hops[k][bestto]); dval = dvals[neighbor][l] + maxdval; movebilist(&listspace[l][neighbor], &buckets[group][k][dval], &buckets[group][k][dval + diff]); dvals[neighbor][l] += diff; dval += diff; if (dval > tops[group][k]) { tops[group][k] = dval; } l++; } } } } if (DEBUG_KL == DebugFlagKL.PrintBucket) { pbuckets(buckets, listspace, maxdval, nsets); } } /* Done with a pass; should we actually perform any swaps? */ bptr = movelist; if (bestg > 0 || (bestg != bestg_min && !balanced && enforce_balance) || (bestg != bestg_min && balance_trouble)) { improved += (int)bestg; for (i = 1; i <= beststep; i++) { vtx = ((int)(bptr - listspace[0])) / size; bestto = (int)(ulong)bptr->prev; startweight[bestto] += graph[vtx]->vwgt; startweight[-sets[vtx] - 1] -= graph[vtx]->vwgt; sets[vtx] = bestto; bptr = bptr->next; } deltaminus = deltaplus = 0; for (i = 0; i < nsets; i++) { if (startweight[i] - goal[i] > deltaplus) { deltaplus = startweight[i] - goal[i]; } else if (goal[i] - startweight[i] > deltaminus) { deltaminus = goal[i] - startweight[i]; } } /* * printf(" deltaplus = %f, deltaminus = %f, max_dev = %d\n", deltaplus, deltaminus, max_dev); */ balanced = (deltaplus + deltaminus <= max_dev); } else { nbad++; } if (!balanced || bptr == movelist) { if (enforce_balance) { if (enforce_balance_hard) { balance_trouble = true; } enforce_balance_hard = true; } enforce_balance = true; nbad++; } worth_undoing = (step < undo_frac * nvtxs); done = (nbad >= nbadtries && balanced); if (KL_MAX_PASS > 0) { done = done || (npass == KL_MAX_PASS && balanced); } if (!done) /* Prepare for next pass. */ { if (KL_UNDO_LIST && worth_undoing && !balance_trouble) { /* Make a list of modified vertices for next bucketsort. */ /* Also, ensure these vertices are removed from their buckets. */ list_length = make_kl_list(graph, movelist, buckets, listspace, sets, nsets, bspace, dvals, maxdval); } } if (done || !(KL_UNDO_LIST && worth_undoing && !balance_trouble)) { /* Restore set numbers of remaining, altered vertices. */ while (bptr != null) { vtx = ((int)(bptr - listspace[0])) / size; sets[vtx] = -sets[vtx] - 1; bptr = bptr->next; } list_length = nvtxs; } if (done && *bndy_list != null) { make_bndy_list(graph, movelist, buckets, listspace, sets, nsets, bspace, tops, bndy_list); } } if (DEBUG_KL != DebugFlagKL.NoDebugging) { Console.WriteLine(" KL required {0:d} passes to improve by {1:d}.", npass, improved); } Marshal.FreeHGlobal((IntPtr)loose); Marshal.FreeHGlobal((IntPtr)locked); Marshal.FreeHGlobal((IntPtr)weightsum); Marshal.FreeHGlobal((IntPtr)bspace); return(false); }