Ejemplo n.º 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);
        }
Ejemplo n.º 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);
        }
Ejemplo n.º 3
0
 private static void init_cube_edata(refine_edata *edata, /* desire data for current edge */
                                     int node1,           /* processor incident to current wire */
                                     int dim,             /* direction of wire */
                                     int mask             /* bit set in wire dimension */
                                     )
 {
     edata->node1 = (short)node1;
     edata->node2 = (short)(node1 ^ mask);
     edata->dim   = (short)dim;
 }
Ejemplo n.º 4
0
        /* Initialize the mapping of sets to endpoints of wires in the mesh. */
        public static void init_mesh_edata(refine_edata *edata, /* desire data for all edges */
                                           int[] mesh_dims      /*[3]*/ /* dimensions of mesh */
                                           )
        {
            int wire;    /* loops through wires */
            int i, j, k; /* loop counters */

            wire = 0;
            /* First do all the x-axis wires. */
            for (k = 0; k < mesh_dims[2]; k++)
            {
                for (j = 0; j < mesh_dims[1]; j++)
                {
                    for (i = 0; i < mesh_dims[0] - 1; i++)
                    {
                        edata[wire].node1 = (short)(i + mesh_dims[0] * (j + k * mesh_dims[1]));
                        edata[wire].node2 = (short)(i + 1 + mesh_dims[0] * (j + k * mesh_dims[1]));
                        edata[wire].dim   = 0;
                        wire++;
                    }
                }
            }

            /* Now do all the y-axis wires. */
            for (k = 0; k < mesh_dims[2]; k++)
            {
                for (j = 0; j < mesh_dims[1] - 1; j++)
                {
                    for (i = 0; i < mesh_dims[0]; i++)
                    {
                        edata[wire].node1 = (short)(i + mesh_dims[0] * (j + k * mesh_dims[1]));
                        edata[wire].node2 = (short)(i + mesh_dims[0] * (j + 1 + k * mesh_dims[1]));
                        edata[wire].dim   = 1;
                        wire++;
                    }
                }
            }

            /* Finally, do all the z-axis wires. */
            for (k = 0; k < mesh_dims[2] - 1; k++)
            {
                for (j = 0; j < mesh_dims[1]; j++)
                {
                    for (i = 0; i < mesh_dims[0]; i++)
                    {
                        edata[wire].node1 = (short)(i + mesh_dims[0] * (j + k * mesh_dims[1]));
                        edata[wire].node2 = (short)(i + mesh_dims[0] * (j + (k + 1) * mesh_dims[1]));
                        edata[wire].dim   = 2;
                        wire++;
                    }
                }
            }
        }
Ejemplo n.º 5
0
        find_edge_cube(int node,            /* processor node */
                       int dim,             /* direction of edge from node */
                       refine_edata *edata, /* data structure for edge preferences */
                       int nsets_tot        /* total number of processors */
                       )
        {
            refine_edata *eguy;  /* returned pointer to edge info */
            int           index; /* computed index into edata */

            /* Squeeze out bit dim from node number. */
            index  = node ^ ((node >> dim) << dim);
            index ^= ((node >> (dim + 1)) << dim);
            index += dim * nsets_tot / 2;

            eguy = &(edata[index]);

            return(eguy);
        }
Ejemplo n.º 6
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;
            }
        }
Ejemplo n.º 7
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);
        }
Ejemplo n.º 8
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;
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="vertex">vertex in comm_graph</param>
        /// <param name="dim">direction of edge from node</param>
        /// <param name="edata">data structure for edge preferences</param>
        /// <param name="mesh_dims">dimensions of mesh</param>
        /// <param name="vtx2node">maps comm_graph vtxs to processors</param>
        private static refine_edata *find_edge_mesh(int vertex, int dim, refine_edata *edata, int[] mesh_dims, int *vtx2node)
        {
            refine_edata *eguy;        /* returned pointer to edge info */
            int           dir;         /* higher or lower direction? */
            int           my_node;     /* processor vertex assigned to */

            int[] my_loc = new int[3]; /* location of my processor */
            int   index  = 0;          /* computed index into edata */

            if (dim < 0)
            {
                dir = -1;
                dim = -(dim + 1);
            }
            else
            {
                dir = 1;
            }

            my_node   = vtx2node[vertex];
            my_loc[0] = my_node % mesh_dims[0];
            my_loc[1] = (my_node / mesh_dims[0]) % mesh_dims[1];
            my_loc[2] = my_node / (mesh_dims[0] * mesh_dims[1]);

            if ((my_loc[dim] == 0 && dir == -1) || (my_loc[dim] == mesh_dims[dim] - 1 && dir == 1))
            {
                eguy = null;
            }

            else
            {
                /* Figure out where edge is in data structure. */
                /* Note: indexing must match with that in init_mesh_edata. */
                if (dir < 0)
                {
                    --my_loc[dim];
                }

                if (dim == 0)
                {
                    /* Edge in x-direction. */
                    index = (mesh_dims[0] - 1) * mesh_dims[1] * my_loc[2] + (mesh_dims[0] - 1) * my_loc[1] +
                            my_loc[0];
                }

                else if (dim == 1)
                {
                    /* Edge in y-direction. */
                    index = (mesh_dims[0] - 1) * mesh_dims[1] * mesh_dims[2] +
                            mesh_dims[0] * (mesh_dims[1] - 1) * my_loc[2] + mesh_dims[0] * my_loc[1] + my_loc[0];
                }
                else if (dim == 2)
                {
                    /* Edge in z-direction. */
                    index = (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] * my_loc[2] + mesh_dims[0] * my_loc[1] + my_loc[0];
                }

                eguy = &(edata[index]);
            }

            return(eguy);
        }
Ejemplo n.º 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);
        }