private static void update_cube_edata(int vertex, /* graph vertex being worked on */ int dim, /* mesh dimension to be adjusted */ refine_edata *edata, /* data structure for edge preferences */ refine_vdata *vdata, /* data structure for vertex preferences */ vtx_data **comm_graph, /* communication graph */ int *node2vtx, /* maps processors to comm_graph vtxs */ int *vtx2node, /* maps comm_graph vtxs to processors */ int nsets_tot, /* total number of processors */ double *best_desire, /* best desire seen */ int imax, /* offset in desire_ptr array */ refine_edata **desire_ptr /* buckets for desire values */ ) { refine_edata *eguy; /* data for desired edge */ float old_desire; /* original desire for edge to flip */ float new_desire; /* new desire for edge to flip */ int node; /* node number of vertex */ int k; /* index into desire_ptr array */ node = vtx2node[vertex]; eguy = find_edge_cube(node, dim, edata, nsets_tot); old_desire = eguy->swap_desire; new_desire = (float)compute_cube_edata(eguy, vdata, nsets_tot, comm_graph, node2vtx); if (new_desire != old_desire) /* Update linked list if necessary. */ { eguy->swap_desire = new_desire; if (new_desire > *best_desire) { *best_desire = new_desire; } /* Remove eguy from it's current place in list. */ if (eguy->prev == null) { /* Round up for index into desire_ptr. */ if (old_desire >= 0) { k = (int)old_desire; if (k != old_desire) { k++; } } else { k = (int)-old_desire; if (k != -old_desire) { k++; } k = -k; } k += imax; desire_ptr[k] = eguy->next; } else { eguy->prev->next = eguy->next; } if (eguy->next != null) { eguy->next->prev = eguy->prev; } /* Now add eguy to it's new desire bucket. */ if (new_desire >= 0) { k = (int)new_desire; if (k != new_desire) { k++; } } else { k = (int)-new_desire; if (k != -new_desire) { k++; } k = -k; } k += imax; eguy->prev = null; eguy->next = desire_ptr[k]; if (desire_ptr[k] != null) { desire_ptr[k]->prev = eguy; } desire_ptr[k] = eguy; } }
/// <summary> /// /// </summary> /// <param name="vertex">graph vertex being worked on</param> /// <param name="dim">mesh dimension to be adjusted</param> /// <param name="edata">data structure for edge preferences</param> /// <param name="vdata">data structure for vertex preferences</param> /// <param name="comm_graph">communication graph</param> /// <param name="mesh_dims">extent of mesh</param> /// <param name="node2vtx">maps mesh nodes to comm_graph vtxs</param> /// <param name="vtx2node">maps mesh nodes to comm_graph vtxs</param> /// <param name="best_desire">best desire seen</param> /// <param name="imax">offset in desire_ptr array</param> /// <param name="desire_ptr">buckets for desire values</param> public static void update_mesh_edata(int vertex, int dim, refine_edata *edata, refine_vdata *vdata, vtx_data **comm_graph, int[] mesh_dims /*[3]*/, int *node2vtx, int *vtx2node, double *best_desire, int imax, refine_edata **desire_ptr) { int i; /* loop counter */ for (i = 0; i < 2; i++) { /* Have to adjust two edges. */ dim = -(dim + 1); var eguy = find_edge_mesh(vertex, dim, edata, mesh_dims, vtx2node); /* data for desired edge */ if (eguy == null) { continue; } var old_desire = eguy->swap_desire; /* original desire for edge to flip */ var new_desire = (float)compute_mesh_edata(eguy, vdata, mesh_dims, comm_graph, node2vtx); /* new desire for edge to flip */ if (new_desire == old_desire) { continue; } /* Update linked list if necessary. */ eguy->swap_desire = new_desire; if (new_desire > *best_desire) { *best_desire = new_desire; } /* Remove eguy from it's current place in list. */ int k; /* loop counter */ if (eguy->prev == null) { /* Round up for index into desire_ptr. */ if (old_desire >= 0) { k = (int)old_desire; if (k != old_desire) { k++; } } else { k = (int)-old_desire; if (k != -old_desire) { k++; } k = -k; } k += imax; desire_ptr[k] = eguy->next; } else { eguy->prev->next = eguy->next; } if (eguy->next != null) { eguy->next->prev = eguy->prev; } /* Now add eguy to it's new desire bucket. */ if (new_desire >= 0) { k = (int)new_desire; if (k != new_desire) { k++; } } else { k = (int)-new_desire; if (k != -new_desire) { k++; } k = -k; } k += imax; eguy->prev = null; eguy->next = desire_ptr[k]; if (desire_ptr[k] != null) { desire_ptr[k]->prev = eguy; } desire_ptr[k] = eguy; } }
/* Use a greedy strategy to swap assignments to reduce hops. */ /* Note that because of our graph data structure, set assignments in the graph */ /* begin at 1 instead of at 0. */ public static bool refine_cube(vtx_data **comm_graph, /* graph for communication requirements */ int ndims_tot, /* dimensionality of hypercube */ double maxdesire, /* largest possible desire to flip an edge */ int *vtx2node, /* mapping from comm_graph vtxs to processors */ int *node2vtx /* mapping from processors to comm_graph vtxs */ ) { refine_vdata * vdata = null; /* desire data for vertices */ refine_vdata * vptr; /* loops through vdata */ refine_edata * edata = null; /* desire data for edges */ refine_edata * eptr; /* loops through edata */ refine_edata * eguy; /* one element in edata array */ refine_edata **desire_ptr = null; /* array of desire buckets */ double * desires = null; /* each edge's inclination to flip */ double * dptr; /* loops through desire */ int * indices = null; /* sorted list of desire values */ int * space = null; /* used for sorting disire values */ double best_desire; /* desire of max edge to flip */ int imax; /* maxdesire rounded up */ int nsets_tot; /* total number of sets/processors */ int neighbor; /* neighboring vertex */ int dim; /* loops over cube dimensions */ int mask; /* bit set for current dimension */ int side; /* side of hypercube node is on */ int nwires; /* number of wires in dimension of hypercube */ int nwires_tot; /* total number of wires in hypercube */ int wire; /* loops through all wires */ int node1, node2; /* processors joined by a wire */ int vtx1, vtx2; /* corresponding vertices in comm_graph */ bool error; /* out of space? */ int i, j, k; /* loop counter */ nsets_tot = 1 << ndims_tot; error = true; imax = (int)maxdesire; if (imax != maxdesire) { imax++; } /* This is really just ndims_tot different 1-D problems. */ /* Allocate space for and inititalize the vertex data. */ vdata = (refine_vdata *)Marshal.AllocHGlobal((ndims_tot * nsets_tot + 1) * sizeof(refine_vdata)); if (vdata == null) { goto skip; } /* Compute each node's desires to move or stay put in each direction. */ vptr = vdata; for (dim = 0; dim < ndims_tot; dim++) { mask = 1 << dim; for (i = 1; i <= nsets_tot; i++) { compute_cube_vdata(++vptr, comm_graph, i, mask, vtx2node); } } /* Now allocate space for and initialize the wire data. */ nwires = nsets_tot / 2; nwires_tot = nwires * ndims_tot; edata = (refine_edata *)Marshal.AllocHGlobal((nwires_tot + 1) * sizeof(refine_edata)); if (edata == null) { goto skip; } desires = (double *)Marshal.AllocHGlobal(nwires_tot * sizeof(double)); if (desires == null) { goto skip; } /* Initialize all the wire swap_desire values. */ eptr = edata; dptr = desires; i = 0; for (dim = 0; dim < ndims_tot; dim++) { mask = 1 << dim; for (wire = 0; 2 * wire < nsets_tot; wire++) { /* Insert zero bit at position dim. */ j = (wire >> dim) << (dim + 1); i = (wire << 1) ^ j; j ^= (i >> 1); init_cube_edata(eptr, j, dim, mask); *dptr++ = eptr->swap_desire = (float)compute_cube_edata(eptr, vdata, nsets_tot, comm_graph, node2vtx); eptr++; } } /* Set value for end pointer larger than all others. */ edata[nwires_tot].swap_desire = (float)(2 * find_maxdeg(comm_graph, nsets_tot, true, (float *)null)); /* I now need to sort all the wire preference values */ indices = (int *)Marshal.AllocHGlobal(nwires_tot * sizeof(int)); space = (int *)Marshal.AllocHGlobal(nwires_tot * sizeof(int)); if (indices == null || space == null) { goto skip; } ch_mergesort(desires, nwires_tot, indices, space); Marshal.FreeHGlobal((IntPtr)space); Marshal.FreeHGlobal((IntPtr)desires); space = null; desires = null; best_desire = (edata[indices[nwires_tot - 1]]).swap_desire; /* Now construct buckets of linked lists with desire values. */ if (best_desire > 0) { desire_ptr = (refine_edata **)Marshal.AllocHGlobal((2 * imax + 1) * sizeof(refine_edata *)); if (desire_ptr == null) { goto skip; } for (i = 2 * imax; i >= 0; i--) { desire_ptr[i] = null; } for (i = nwires_tot - 1; i >= 0; i--) { eguy = &(edata[indices[i]]); /* Round the swap desire up. */ if (eguy->swap_desire >= 0) { k = (int)eguy->swap_desire; if (k != eguy->swap_desire) { k++; } } else { k = (int)-eguy->swap_desire; if (k != -eguy->swap_desire) { k++; } k = -k; } k += imax; eguy->prev = null; eguy->next = desire_ptr[k]; if (desire_ptr[k] != null) { desire_ptr[k]->prev = eguy; } desire_ptr[k] = eguy; } } else { desire_ptr = null; } Marshal.FreeHGlobal((IntPtr)indices); indices = null; /* Everything is now set up. Swap sets across wires until no more improvement. */ while (best_desire > 0) { k = (int)(best_desire + 1 + imax); if (k > 2 * imax) { k = 2 * imax; } while (k > imax && desire_ptr[k] == null) { k--; } eguy = desire_ptr[k]; dim = eguy->dim; mask = 1 << dim; node1 = eguy->node1; node2 = eguy->node2; vtx1 = node2vtx[node1]; vtx2 = node2vtx[node2]; /* Swap the sets. */ node2vtx[node1] = vtx2; node2vtx[node2] = vtx1; vtx2node[vtx1] = node2; vtx2node[vtx2] = node1; /* Update all the vdata fields for vertices effected by this flip. */ /* First do the vertices adjacent to swapped guys, in swapped dimension. */ side = node1 & mask; for (j = 1; j < comm_graph[vtx1]->nedges; j++) { neighbor = comm_graph[vtx1]->edges[j]; if (neighbor != vtx2) { update_cube_vdata(side, mask, vtx2node[neighbor], comm_graph[vtx1]->ewgts[j], &(vdata[dim * nsets_tot + neighbor])); } } side = node2 & mask; for (j = 1; j < comm_graph[vtx2]->nedges; j++) { neighbor = comm_graph[vtx2]->edges[j]; if (neighbor != vtx1) { update_cube_vdata(side, mask, vtx2node[neighbor], comm_graph[vtx2]->ewgts[j], &(vdata[dim * nsets_tot + neighbor])); } } /* Now recompute all preferences for vertices that were moved. */ for (j = 0; j < ndims_tot; j++) { k = 1 << j; compute_cube_vdata(&(vdata[j * nsets_tot + vtx1]), comm_graph, vtx1, k, vtx2node); compute_cube_vdata(&(vdata[j * nsets_tot + vtx2]), comm_graph, vtx2, k, vtx2node); } /* Now I can update the values of all the edges associated with all the * effected vertices. Note that these include cube neighbors of node1 and * node2 in addition to the dim-edges of graph neighbors of vtx1 and vtx2. */ /* For each neighbor vtx, look at wire in this direction. If desire hasn't changed, * return. Otherwise, pick him up and move him in desire list. Similarly for all * directional neighbors of node1 and node2. */ for (j = 1; j < comm_graph[vtx1]->nedges; j++) { neighbor = comm_graph[vtx1]->edges[j]; if (neighbor != vtx2) { update_cube_edata(neighbor, dim, edata, vdata, comm_graph, node2vtx, vtx2node, nsets_tot, &best_desire, imax, desire_ptr); } } for (j = 1; j < comm_graph[vtx2]->nedges; j++) { neighbor = comm_graph[vtx2]->edges[j]; if (neighbor != vtx1) { update_cube_edata(neighbor, dim, edata, vdata, comm_graph, node2vtx, vtx2node, nsets_tot, &best_desire, imax, desire_ptr); } } for (j = 0; j < ndims_tot; j++) { update_cube_edata(vtx1, j, edata, vdata, comm_graph, node2vtx, vtx2node, nsets_tot, &best_desire, imax, desire_ptr); update_cube_edata(vtx2, j, edata, vdata, comm_graph, node2vtx, vtx2node, nsets_tot, &best_desire, imax, desire_ptr); } k = (int)(best_desire + 1 + imax); if (k > 2 * imax) { k = 2 * imax; } while (k > imax && desire_ptr[k] == null) { k--; } best_desire = k - imax; } error = false; skip: Marshal.FreeHGlobal((IntPtr)space); Marshal.FreeHGlobal((IntPtr)desires); Marshal.FreeHGlobal((IntPtr)indices); Marshal.FreeHGlobal((IntPtr)desire_ptr); Marshal.FreeHGlobal((IntPtr)vdata); Marshal.FreeHGlobal((IntPtr)edata); return(error); }
/* Use a greedy strategy to swap assignments to reduce hops. */ /* Note that because of our graph data structure, set assignments in the graph */ /* begin at 1 instead of at 0. */ public static bool refine_mesh(vtx_data **comm_graph, /* graph for communication requirements */ int cube_or_mesh, /* number of dimensions in mesh */ int[] mesh_dims /*[3]*/, /* dimensions of mesh */ double maxdesire, /* largest possible desire to flip an edge */ int *vtx2node, /* mapping from comm_graph vtxs to mesh nodes */ int *node2vtx /* mapping from mesh nodes to comm_graph vtxs */ ) { refine_vdata * vdata = null; /* desire data for all vertices */ refine_vdata * vptr; /* loops through vdata */ refine_edata * edata = null; /* desire data for all edges */ refine_edata * eguy; /* one element in edata array */ refine_edata **desire_ptr = null; /* array of desire buckets */ double * desires = null; /* each edge's inclination to flip */ int * indices = null; /* sorted list of desire values */ int * space = null; /* used for sorting disire values */ double best_desire; /* highest desire of edge to flip */ int imax; /* maxdesire rounded up */ int nsets_tot; /* total number of sets/processors */ int neighbor; /* neighboring vertex */ int dim; /* loops over mesh dimensions */ int nwires; /* number of wires in processor mesh */ int wire; /* loops through all wires */ int node1, node2; /* processors joined by a wire */ int vtx1, vtx2; /* corresponding vertices in comm_graph */ int loc1, loc2; /* location of vtxs in flipping dimension */ bool error; /* out of space? */ int i, j, k; /* loop counter */ error = true; nsets_tot = mesh_dims[0] * mesh_dims[1] * mesh_dims[2]; imax = (int)maxdesire; if (imax != maxdesire) { imax++; } vdata = (refine_vdata *)Marshal.AllocHGlobal((cube_or_mesh * nsets_tot + 1) * sizeof(refine_vdata)); if (vdata == null) { goto skip; } /* Compute each node's desires to move or stay put. */ vptr = vdata; for (dim = 0; dim < cube_or_mesh; dim++) { for (i = 1; i <= nsets_tot; i++) { compute_mesh_vdata(++vptr, comm_graph, i, vtx2node, mesh_dims, dim); } } nwires = (mesh_dims[0] - 1) * mesh_dims[1] * mesh_dims[2] + mesh_dims[0] * (mesh_dims[1] - 1) * mesh_dims[2] + mesh_dims[0] * mesh_dims[1] * (mesh_dims[2] - 1); edata = (refine_edata *)Marshal.AllocHGlobal((nwires + 1) * sizeof(refine_edata)); desires = (double *)Marshal.AllocHGlobal(nwires * sizeof(double)); if (desires == null) { goto skip; } /* Initialize all the edge values. */ init_mesh_edata(edata, mesh_dims); for (wire = 0; wire < nwires; wire++) { desires[wire] = edata[wire].swap_desire = (float)compute_mesh_edata(&(edata[wire]), vdata, mesh_dims, comm_graph, node2vtx); } /* Set special value for end pointer. */ edata[nwires].swap_desire = 2.0f * (float)find_maxdeg(comm_graph, nsets_tot, true, (float *)null); /* I now need to sort all the wire preference values */ indices = (int *)Marshal.AllocHGlobal(nwires * sizeof(int)); space = (int *)Marshal.AllocHGlobal(nwires * sizeof(int)); if (indices == null || space == null) { goto skip; } ch_mergesort(desires, nwires, indices, space); Marshal.FreeHGlobal((IntPtr)space); Marshal.FreeHGlobal((IntPtr)desires); space = null; desires = null; best_desire = (edata[indices[nwires - 1]]).swap_desire; /* Now construct a buckets of linked lists with desire values. */ if (best_desire > 0) { desire_ptr = (refine_edata **)Marshal.AllocHGlobal((2 * imax + 1) * sizeof(refine_edata *)); if (desire_ptr == null) { goto skip; } for (i = 2 * imax; i >= 0; i--) { desire_ptr[i] = null; } for (i = nwires - 1; i >= 0; i--) { eguy = &(edata[indices[i]]); /* Round the swap desire up. */ if (eguy->swap_desire >= 0) { k = (int)eguy->swap_desire; if (k != eguy->swap_desire) { k++; } } else { k = (int)-eguy->swap_desire; if (k != -eguy->swap_desire) { k++; } k = -k; } k += imax; eguy->prev = null; eguy->next = desire_ptr[k]; if (desire_ptr[k] != null) { desire_ptr[k]->prev = eguy; } desire_ptr[k] = eguy; } } else { desire_ptr = null; } Marshal.FreeHGlobal((IntPtr)indices); indices = null; loc1 = 0; loc2 = 0; /* Everything is now set up. Swap sets across wires until no more improvement. */ while (best_desire > 0) { k = (int)(best_desire + 1 + imax); if (k > 2 * imax) { k = 2 * imax; } while (k > imax && desire_ptr[k] == null) { k--; } eguy = desire_ptr[k]; dim = eguy->dim; node1 = eguy->node1; node2 = eguy->node2; vtx1 = node2vtx[node1]; vtx2 = node2vtx[node2]; if (dim == 0) { loc1 = node1 % mesh_dims[0]; loc2 = node2 % mesh_dims[0]; } else if (dim == 1) { loc1 = (node1 / mesh_dims[0]) % mesh_dims[1]; loc2 = (node2 / mesh_dims[0]) % mesh_dims[1]; } else if (dim == 2) { loc1 = node1 / (mesh_dims[0] * mesh_dims[1]); loc2 = node2 / (mesh_dims[0] * mesh_dims[1]); } /* Now swap the vertices. */ node2vtx[node1] = vtx2; node2vtx[node2] = vtx1; vtx2node[vtx1] = node2; vtx2node[vtx2] = node1; /* First update all the vdata fields for vertices effected by this flip. */ for (j = 1; j < comm_graph[vtx1]->nedges; j++) { neighbor = comm_graph[vtx1]->edges[j]; if (neighbor != vtx2) { update_mesh_vdata(loc1, loc2, dim, comm_graph[vtx1]->ewgts[j], vdata, mesh_dims, neighbor, vtx2node); } } for (j = 1; j < comm_graph[vtx2]->nedges; j++) { neighbor = comm_graph[vtx2]->edges[j]; if (neighbor != vtx1) { update_mesh_vdata(loc2, loc1, dim, comm_graph[vtx2]->ewgts[j], vdata, mesh_dims, neighbor, vtx2node); } } /* Now recompute all preferences for vertices that were moved. */ for (j = 0; j < cube_or_mesh; j++) { compute_mesh_vdata(&(vdata[j * nsets_tot + vtx1]), comm_graph, vtx1, vtx2node, mesh_dims, j); compute_mesh_vdata(&(vdata[j * nsets_tot + vtx2]), comm_graph, vtx2, vtx2node, mesh_dims, j); } /* Now I can update the values of all the edges associated with all the * effected vertices. Note that these include mesh neighbors of node1 and * node2 in addition to the dim-edges of graph neighbors of vtx1 and vtx2. */ /* For each neighbor vtx, look at -1 and +1 edge. If desire hasn't changed, * return. Otherwise, pick him up and move him. Similarly for all * directional neighbors of node1 and node2. */ for (j = 1; j < comm_graph[vtx1]->nedges; j++) { neighbor = comm_graph[vtx1]->edges[j]; if (neighbor != vtx2) { update_mesh_edata(neighbor, dim, edata, vdata, comm_graph, mesh_dims, node2vtx, vtx2node, &best_desire, imax, desire_ptr); } } for (j = 1; j < comm_graph[vtx2]->nedges; j++) { neighbor = comm_graph[vtx2]->edges[j]; if (neighbor != vtx1) { update_mesh_edata(neighbor, dim, edata, vdata, comm_graph, mesh_dims, node2vtx, vtx2node, &best_desire, imax, desire_ptr); } } for (j = 0; j < cube_or_mesh; j++) { update_mesh_edata(vtx1, j, edata, vdata, comm_graph, mesh_dims, node2vtx, vtx2node, &best_desire, imax, desire_ptr); update_mesh_edata(vtx2, j, edata, vdata, comm_graph, mesh_dims, node2vtx, vtx2node, &best_desire, imax, desire_ptr); } k = (int)(best_desire + 1 + imax); if (k > 2 * imax) { k = 2 * imax; } while (k > imax && desire_ptr[k] == null) { k--; } best_desire = k - imax; } error = false; skip: Marshal.FreeHGlobal((IntPtr)indices); Marshal.FreeHGlobal((IntPtr)space); Marshal.FreeHGlobal((IntPtr)desires); Marshal.FreeHGlobal((IntPtr)desire_ptr); Marshal.FreeHGlobal((IntPtr)vdata); Marshal.FreeHGlobal((IntPtr)edata); return(error); }