Beispiel #1
0
        private static double compute_cube_edata(refine_edata *edata,   /* desire data for current edge */
                                                 refine_vdata *vdata,   /* data for all vertices */
                                                 int nsets_tot,         /* total number of processors */
                                                 vtx_data **comm_graph, /* communication graph */
                                                 int *node2vtx          /* maps mesh nodes to graph vertices */
                                                 )
        {
            double desire;     /* edge's interest in flipping */
            float  ewgt;       /* edge weight */
            int    offset;     /* offset into vdata array */
            int    vtx1, vtx2; /* vertices on either side of wire */

            vtx1   = node2vtx[edata->node1];
            vtx2   = node2vtx[edata->node2];
            offset = nsets_tot * edata->dim;

            desire = (vdata[offset + vtx1].above - vdata[offset + vtx1].same) +
                     (vdata[offset + vtx2].above - vdata[offset + vtx2].same);

            /* Subtract off potential doubly counted edge. */
            if (is_an_edge(comm_graph[vtx1], vtx2, &ewgt))
            {
                desire -= 2 * ewgt;
            }

            return(desire);
        }
Beispiel #2
0
        public static double compute_mesh_edata(refine_edata *edata,     /* desire data for current edge */
                                                refine_vdata *vdata,     /* data for all vertices */
                                                int[] mesh_dims /*[3]*/, /* dimensions of processor mesh */
                                                vtx_data **comm_graph,   /* communication graph */
                                                int *node2vtx            /* maps mesh nodes to graph vertices */
                                                )
        {
            double desire;     /* edge's interest in flipping */
            float  ewgt;       /* edge weight */
            int    vtx1, vtx2; /* vertices on either side of wire */
            int    off;        /* index into vdata */

            vtx1 = node2vtx[edata->node1];
            vtx2 = node2vtx[edata->node2];

            off = edata->dim * mesh_dims[0] * mesh_dims[1] * mesh_dims[2];

            desire = (vdata[off + vtx1].above - vdata[off + vtx1].below - vdata[off + vtx1].same) +
                     (vdata[off + vtx2].below - vdata[off + vtx2].above - vdata[off + vtx2].same);

            /* Subtract off potential doubly counted edge. */
            if (is_an_edge(comm_graph[vtx1], vtx2, &ewgt))
            {
                desire -= 2 * ewgt;
            }

            return(desire);
        }
Beispiel #3
0
        private static void update_cube_vdata(int old_side,       /* previous side for moved vertex in moved dimension */
                                              int mask,           /* bit set in current dimension */
                                              int neighbor_node,  /* node neighbor vertex assigned to */
                                              double ewgt,        /* weight of edge */
                                              refine_vdata *vdata /* neighbor connected by that edge */
                                              )
        {
            int neighbor_side; /* side of cube neighbor is on */

            neighbor_side = (neighbor_node & mask);

            if (neighbor_side == old_side)
            {
                vdata->above += (float)ewgt;
                vdata->same  -= (float)ewgt;
            }
            else
            {
                vdata->above -= (float)ewgt;
                vdata->same  += (float)ewgt;
            }
        }
Beispiel #4
0
        private static void compute_cube_vdata(refine_vdata *vdata,   /* preference data for a vertex */
                                               vtx_data **comm_graph, /* communication graph data structure */
                                               int vtx,               /* current vertex */
                                               int mask,              /* bit set in current hypercube dimension */
                                               int *vtx2node          /* maps graph vtxs to mesh nodes */
                                               )
        {
            float same;        /* my preference to stay where I am */
            float change;      /* my preference to change this bit */
            float ewgt;        /* weight of an edge */
            int   neighbor;    /* neighboring vtx in comm_graph */
            int   my_side;     /* which side of hypercube I'm on */
            int   neighb_side; /* which side of hypercube neighbor's on */
            int   j;           /* loop counter */

            my_side = (vtx2node[vtx] & mask);

            change = 0;
            same   = 0;
            for (j = 1; j < comm_graph[vtx]->nedges; j++)
            {
                neighbor = comm_graph[vtx]->edges[j];
                ewgt     = comm_graph[vtx]->ewgts[j];

                neighb_side = (vtx2node[neighbor] & mask);

                if (neighb_side != my_side)
                {
                    change += ewgt;
                }
                else
                {
                    same += ewgt;
                }
            }
            vdata->same  = same;
            vdata->above = change;
        }
Beispiel #5
0
        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;
            }
        }
Beispiel #6
0
        /* 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);
        }
Beispiel #7
0
        /// <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;
            }
        }
Beispiel #8
0
        public static void compute_mesh_vdata(refine_vdata *vdata,     /* preference data for a vertex */
                                              vtx_data **comm_graph,   /* communication graph data structure */
                                              int vtx,                 /* current vertex */
                                              int *vtx2node,           /* maps graph vtxs to mesh nodes */
                                              int[] mesh_dims /*[3]*/, /* size of mesh */
                                              int dim                  /* dimension we are currently working in */
                                              )
        {
            float above;      /* my preference to move up in each dimension */
            float below;      /* my preference to move down in each dimension */
            float same;       /* my preference to stay where I am */
            int   my_loc;     /* my location in mesh */
            int   neighb_loc; /* neighbor's location in mesh */
            float ewgt;       /* weight of an edge */
            int   node;       /* set vertex is assigned to */
            int   neighbor;   /* neighboring vtx in comm_graph */
            int   j;          /* loop counter */

            node = vtx2node[vtx];

            neighb_loc = 0;
            my_loc     = 0;

            if (dim == 0)
            {
                my_loc = node % mesh_dims[0];
            }
            else if (dim == 1)
            {
                my_loc = (node / mesh_dims[0]) % mesh_dims[1];
            }
            else if (dim == 2)
            {
                my_loc = node / (mesh_dims[0] * mesh_dims[1]);
            }

            below = above = same = 0;
            for (j = 1; j < comm_graph[vtx]->nedges; j++)
            {
                neighbor = comm_graph[vtx]->edges[j];
                ewgt     = comm_graph[vtx]->ewgts[j];
                node     = vtx2node[neighbor];

                if (dim == 0)
                {
                    neighb_loc = node % mesh_dims[0];
                }
                else if (dim == 1)
                {
                    neighb_loc = (node / mesh_dims[0]) % mesh_dims[1];
                }
                else if (dim == 2)
                {
                    neighb_loc = node / (mesh_dims[0] * mesh_dims[1]);
                }

                if (neighb_loc < my_loc)
                {
                    below += ewgt;
                }
                else if (neighb_loc > my_loc)
                {
                    above += ewgt;
                }
                else
                {
                    same += ewgt;
                }
            }

            vdata->below = below;
            vdata->above = above;
            vdata->same  = same;
        }
Beispiel #9
0
        public static void update_mesh_vdata(int old_loc,             /* previous node for moved vertex in moved dimension */
                                             int new_loc,             /* new node for moved vertex in moved dimension */
                                             int dim,                 /* dimension that was changed */
                                             double ewgt,             /* weight of edge */
                                             refine_vdata *vdata,     /* array of vertex data */
                                             int[] mesh_dims /*[3]*/, /* size of processor mesh */
                                             int neighbor,            /* vertex impacted by flip */
                                             int *vtx2node            /* mapping from comm_graph vtxs to processors */
                                             )
        {
            refine_vdata *vptr          = null; /* correct element in vdata */
            int           offset        = 0;    /* index into vdata array */
            int           my_loc        = 0;    /* my location in relevant dimension */
            int           neighbor_node = 0;    /* processor neighbor assigned to */

            neighbor_node = vtx2node[neighbor];

            if (dim == 0)
            {
                offset = 0;
                my_loc = neighbor_node % mesh_dims[0];
            }
            else if (dim == 1)
            {
                offset = mesh_dims[0] * mesh_dims[1] * mesh_dims[2];
                my_loc = (neighbor_node / mesh_dims[0]) % mesh_dims[1];
            }
            else if (dim == 2)
            {
                offset = 2 * mesh_dims[0] * mesh_dims[1] * mesh_dims[2];
                my_loc = neighbor_node / (mesh_dims[0] * mesh_dims[1]);
            }

            vptr = &vdata[offset + neighbor];

            /* If I'm far away from the flipped edge, I'm not effected. */
            if (!((old_loc < my_loc && new_loc < my_loc) || (old_loc > my_loc && new_loc > my_loc)))
            {
                if (old_loc < my_loc)
                {
                    /* Old moves to the right to line up with me. */
                    vptr->same  += (float)ewgt;
                    vptr->below -= (float)ewgt;
                }

                else if (old_loc > my_loc)
                {
                    /* Old moves to the left to line up with me. */
                    vptr->same  += (float)ewgt;
                    vptr->above -= (float)ewgt;
                }

                else if (new_loc < my_loc)
                {
                    /* Old moves to the left to pass me. */
                    vptr->same  -= (float)ewgt;
                    vptr->below += (float)ewgt;
                }

                else if (new_loc > my_loc)
                {
                    /* Old moves to the right to pass me. */
                    vptr->same  -= (float)ewgt;
                    vptr->above += (float)ewgt;
                }
            }
        }
Beispiel #10
0
        /* 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);
        }