/* Perform KL between two sets. */ int kl_refine ( struct vtx_data **graph, /* graph data structure */ struct vtx_data **subgraph, /* space for subgraph to refine */ struct bilist *set_list, /* lists of vtxs in each set */ struct bilist *vtx_elems, /* start of storage for lists */ int *new_assign, /* set assignments for all vertices */ int set1, int set2, /* two sets being refined */ int *glob2loc, /* maps vertices to subgraph vertices */ int *loc2glob, /* maps subgraph vertices to vertices */ int *sub_assign, /* new assignment for subgraphs */ int *old_sub_assign, /* current assignment for subgraphs */ int *degrees, /* space for forming subgraphs */ int using_ewgts, /* are edge weights being used? */ int (*hops)[MAXSETS], /* KL set preferences */ double *goal, /* desired set sizes */ int *sizes, /* number of vertices in different sets */ float *term_wgts[], /* space for terminal propagation weights */ int architecture, /* 0 => hypercube, d => d-dimensional mesh */ int mesh_dims[3] /* if mesh, how big is it? */ ) { extern int TERM_PROP; /* perform terminal propagation? */ extern double KL_IMBALANCE; /* fractional imbalance allowed in KL */ struct bilist *ptr; /* element in set_list */ double subgoal[2]; /* goal within two subgraphs */ double weights[2]; /* weights for each set */ double maxdeg; /* largest degree of a vertex */ double ratio; /* set sizes / goals */ int *null_ptr; /* argument to klspiff */ int vwgt_max; /* largest vertex weight */ int max_dev; /* largest set deviation allowed in KL */ int subnvtxs; /* number of vtxs in subgraph */ int vwgt_sum1; /* sum of vertex wgts in first set */ int vwgt_sum2; /* sum of vertex wgts in second set */ int subnedges; /* number of edges in subgraph */ int setA, setB; /* two sets being refined */ int nsame; /* number of vertices not moved */ int vtx; /* vertex in subgraph */ int i; /* loop counter */ double find_maxdeg(); void make_maps_ref(), make_subgraph(), remake_graph(); void klspiff(), make_terms_ref(), count_weights(); /* Compute all the quantities I'll need. */ null_ptr = NULL; make_maps_ref(graph, set_list, vtx_elems, new_assign, sub_assign, set1, set2, glob2loc, loc2glob, &subnvtxs, &vwgt_max, &vwgt_sum1, &vwgt_sum2); for (i = 1; i <= subnvtxs; i++) old_sub_assign[i] = sub_assign[i]; /* Set up goals for this KL invocation. */ ratio = (vwgt_sum1 + vwgt_sum2) / (goal[set1] + goal[set2]); subgoal[0] = ratio * goal[set1]; subgoal[1] = ratio * goal[set2]; if (TERM_PROP) { make_terms_ref(graph, using_ewgts, subnvtxs, loc2glob, set1, set2, new_assign, architecture, mesh_dims, term_wgts); } /* New_assign has overwritten set2 with set1. */ make_subgraph(graph, subgraph, subnvtxs, &subnedges, new_assign, set1, glob2loc, loc2glob, degrees, using_ewgts); maxdeg = find_maxdeg(subgraph, subnvtxs, using_ewgts, (float *) NULL); count_weights(subgraph, subnvtxs, sub_assign, 2, weights, (vwgt_max != 1)); max_dev = vwgt_max; ratio = (subgoal[0] + subgoal[1]) * KL_IMBALANCE / 2; if (ratio > max_dev) { max_dev = ratio; } klspiff(subgraph, subnvtxs, sub_assign, 2, hops, subgoal, term_wgts, max_dev, maxdeg, using_ewgts, &null_ptr, weights); /* Figure out which modification leaves most vertices intact. */ nsame = 0; for (i = 1; i <= subnvtxs; i++) { if (old_sub_assign[i] == sub_assign[i]) nsame++; } if (2 * nsame > subnvtxs) { setA = set1; setB = set2; } else { setA = set2; setB = set1; } /* Now update the assignments. */ sizes[setA] = sizes[setB] = 0; for (i = 1; i <= subnvtxs; i++) { vtx = loc2glob[i]; /* Update the set_lists. */ ptr = &(vtx_elems[vtx]); if (ptr->next != NULL) { ptr->next->prev = ptr->prev; } if (ptr->prev != NULL) { ptr->prev->next = ptr->next; } if (sub_assign[i] == 0) { new_assign[vtx] = (int) setA; ++sizes[setA]; ptr->next = set_list[setA].next; if (ptr->next != NULL) ptr->next->prev = ptr; ptr->prev = &(set_list[setA]); set_list[setA].next = ptr; } else { new_assign[vtx] = (int) setB; ++sizes[setB]; ptr->next = set_list[setB].next; if (ptr->next != NULL) ptr->next->prev = ptr; ptr->prev = &(set_list[setB]); set_list[setB].next = ptr; } } remake_graph(subgraph, subnvtxs, loc2glob, degrees, using_ewgts); return(nsame != subnvtxs); }
void connect_enforce(struct vtx_data **graph, /* data structure for graph */ int nvtxs, /* number of vertices in full graph */ int using_ewgts, /* are edge weights being used? */ int * assignment, /* set number of each vtx (length n) */ double * goal, /* desired sizes for each set */ int nsets_tot, /* total number sets created */ int * total_move, /* total number of vertices moved */ int * max_move /* largest connected component moved */ ) { struct vtx_data **subgraph; /* data structure for domain graph */ int subnvtxs; /* number of vertices in a domain */ int subnedges; /* number of edges in a domain */ struct heap * heap; /* data structure for sorting set sizes */ int * heap_map; /* pointers from sets to heap locations */ int * list_ptrs; /* header of vtx list for each domain */ int * setlists; /* linked list of vtxs for each domain */ int * vtxlist; /* space for breadth first search list */ int * comp_lists; /* list of vtxs in each connected comp */ int * clist_ptrs; /* pointers to heads of comp_lists */ int * subsets; /* list of active domains (all of them) */ int * subsets2; /* list of active domains (all of them) */ double * set_size; /* weighted sizes of different partitions */ double size; /* size of subset being moved to new domain */ int * bndy_list; /* list of domains adjacent to component */ double * bndy_size; /* size of these boundaries */ double * comp_size; /* sizes of different connected components */ double comp_size_max; /* size of largest connected component */ int comp_max_index = 0; /* which component is largest? */ int * glob2loc; /* global to domain renumbering */ int * loc2glob; /* domain to global renumbering */ int * degree; /* number of neighbors of a vertex */ int * comp_flag; /* component number for each vtx */ double ewgt; /* edge weight */ int nbndy; /* number of sets adjecent to component */ int domain; /* which subdomain I'm working on */ int new_domain; /* subdomain to move some vertices to */ double max_bndy; /* max connectivity to other domain */ int ncomps; /* number of connected components */ int change; /* how many vertices change set? */ int max_change; /* largest subset moved together */ int vtx; /* vertex in a connected component */ int set; /* set a neighboring vertex is in */ int i, j, k, l; /* loop counters */ double heap_extract_max(); int make_maps(), find_comps(); void make_setlists(), make_subgraph(), remake_graph(); void heap_build(), heap_update_val(); change = 0; max_change = 0; /* Allocate space & initialize some values. */ set_size = smalloc(nsets_tot * sizeof(double)); bndy_size = smalloc(nsets_tot * sizeof(double)); bndy_list = smalloc(nsets_tot * sizeof(int)); setlists = smalloc((nvtxs + 1) * sizeof(int)); list_ptrs = smalloc(nsets_tot * sizeof(int)); glob2loc = smalloc((nvtxs + 1) * sizeof(int)); loc2glob = smalloc((nvtxs + 1) * sizeof(int)); subsets = smalloc(nsets_tot * sizeof(int)); heap = (struct heap *)smalloc((nsets_tot + 1) * sizeof(struct heap)); heap_map = smalloc(nsets_tot * sizeof(int)); for (i = 0; i < nsets_tot; i++) { set_size[i] = 0; bndy_list[i] = 0; bndy_size[i] = 0; subsets[i] = i; } for (i = 1; i <= nvtxs; i++) { set_size[assignment[i]] += graph[i]->vwgt; } for (i = 0; i < nsets_tot; i++) { heap[i + 1].tag = i; heap[i + 1].val = set_size[i] - goal[i]; } make_setlists(setlists, list_ptrs, nsets_tot, subsets, assignment, NULL, nvtxs, TRUE); heap_build(heap, nsets_tot, heap_map); for (i = 0; i < nsets_tot; i++) { /* Find largest remaining set to work on next */ size = heap_extract_max(heap, nsets_tot - i, &domain, heap_map); /* Construct subdomain graph. */ subnvtxs = make_maps(setlists, list_ptrs, domain, glob2loc, loc2glob); if (subnvtxs > 1) { subgraph = (struct vtx_data **)smalloc((subnvtxs + 1) * sizeof(struct vtx_data *)); degree = smalloc((subnvtxs + 1) * sizeof(int)); make_subgraph(graph, subgraph, subnvtxs, &subnedges, assignment, domain, glob2loc, loc2glob, degree, using_ewgts); /* Find connected components. */ comp_flag = smalloc((subnvtxs + 1) * sizeof(int)); vtxlist = smalloc(subnvtxs * sizeof(int)); ncomps = find_comps(subgraph, subnvtxs, comp_flag, vtxlist); sfree(vtxlist); /* Restore original graph */ remake_graph(subgraph, subnvtxs, loc2glob, degree, using_ewgts); sfree(degree); sfree(subgraph); if (ncomps > 1) { /* Figure out sizes of components */ comp_size = smalloc(ncomps * sizeof(double)); for (j = 0; j < ncomps; j++) { comp_size[j] = 0; } for (j = 1; j <= subnvtxs; j++) { comp_size[comp_flag[j]] += graph[loc2glob[j]]->vwgt; } comp_size_max = 0; for (j = 0; j < ncomps; j++) { if (comp_size[j] > comp_size_max) { comp_size_max = comp_size[j]; comp_max_index = j; } } for (j = 0; j < ncomps; j++) { if (j != comp_max_index) { change += comp_size[j]; if (comp_size[j] > max_change) max_change = comp_size[j]; } } sfree(comp_size); /* Make data structures for traversing components */ comp_lists = smalloc((subnvtxs + 1) * sizeof(int)); clist_ptrs = smalloc(ncomps * sizeof(int)); if (ncomps > nsets_tot) { subsets2 = smalloc(ncomps * sizeof(int)); for (j = 0; j < ncomps; j++) subsets2[j] = j; } else subsets2 = subsets; make_setlists(comp_lists, clist_ptrs, ncomps, subsets2, comp_flag, NULL, subnvtxs, TRUE); if (ncomps > nsets_tot) { sfree(subsets2); } /* Move all but the largest component. */ ewgt = 1; for (j = 0; j < ncomps; j++) if (j != comp_max_index) { /* Figure out to which other domain it is most connected. */ nbndy = 0; k = clist_ptrs[j]; while (k != 0) { vtx = loc2glob[k]; for (l = 1; l <= graph[vtx]->nedges; l++) { set = assignment[graph[vtx]->edges[l]]; if (set != domain) { if (bndy_size[set] == 0) bndy_list[nbndy++] = set; if (using_ewgts) ewgt = graph[vtx]->ewgts[l]; bndy_size[set] += ewgt; } } k = comp_lists[k]; } /* Select a new domain. */ /* Instead of just big boundary, penalize too-large sets. */ /* Could be more aggressive to improve balance. */ max_bndy = 0; new_domain = -1; for (k = 0; k < nbndy; k++) { l = bndy_list[k]; if (bndy_size[l] * goal[l] / (set_size[l] + 1) > max_bndy) { new_domain = bndy_list[k]; max_bndy = bndy_size[l] * goal[l] / (set_size[l] + 1); } } if (new_domain == -1) { printf("Error in connect_enforce: new_domain = -1. Disconnected graph?\n"); new_domain = domain; } /* Clear bndy_size array */ for (k = 0; k < nbndy; k++) bndy_size[bndy_list[k]] = 0; k = clist_ptrs[j]; size = 0; while (k != 0) { vtx = loc2glob[k]; assignment[vtx] = new_domain; size += graph[vtx]->vwgt; /* Finally, update setlists and list_ptrs */ /* Note: current domain setlist now bad, but not used again */ setlists[vtx] = list_ptrs[new_domain]; list_ptrs[new_domain] = vtx; k = comp_lists[k]; } /* printf("Updating set %d (from %d) to size %g\n", new_domain, domain, set_size[new_domain] + size - goal[new_domain]); */ if (heap_map[new_domain] > 0) { set_size[new_domain] += size; heap_update_val(heap, heap_map[new_domain], set_size[new_domain] - goal[new_domain], heap_map); } } sfree(clist_ptrs); sfree(comp_lists); } sfree(comp_flag); } } sfree(heap_map); sfree(heap); sfree(subsets); sfree(loc2glob); sfree(glob2loc); sfree(list_ptrs); sfree(setlists); sfree(bndy_list); sfree(bndy_size); sfree(set_size); *total_move = change; *max_move = max_change; }