예제 #1
0
        public static bool klv_init(bilist ***lbucket_ptr, /* space for left bucket sorts */
                                    bilist ***rbucket_ptr, /* space for right bucket sorts */
                                    bilist **llistspace,   /* space for elements of linked lists */
                                    bilist **rlistspace,   /* space for elements of linked lists */
                                    int **ldvals,          /* change in separator for left moves */
                                    int **rdvals,          /* change in separator for right moves */
                                    int nvtxs,             /* number of vertices in the graph */
                                    int maxchange          /* maximum change by moving a vertex */
                                    )
        {
            int sizeb; /* size of set of buckets */
            int sizel; /* size of set of pointers for all vertices */

            /* Allocate appropriate data structures for buckets, and listspace. */

            sizeb = (2 * maxchange + 1) * sizeof(bilist *);
            *lbucket_ptr = (bilist **)Marshal.AllocHGlobal(sizeb);
            *rbucket_ptr = (bilist **)Marshal.AllocHGlobal(sizeb);

            *ldvals = (int *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(int));
            *rdvals = (int *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(int));

            sizel = (nvtxs + 1) * sizeof(bilist);
            *llistspace = (bilist *)Marshal.AllocHGlobal(sizel);
            *rlistspace = (bilist *)Marshal.AllocHGlobal(sizel);

            return(*lbucket_ptr == null || *rbucket_ptr == null || *ldvals == null || *rdvals == null ||
                   *llistspace == null || *rlistspace == null);
        }
예제 #2
0
        private static void p1bucket(bilist **bucket, /* buckets holding bucket list */
                                     bilist *lptr,    /* elements within bucket */
                                     int maxdeg       /* maximum degree of a vertex */
                                     )
        {
            bilist *bptr; /* loops through list at a bucket */
            int     val;  /* element in a bucket */
            int     size; /* array spacing */
            int     i;    /* loop counter */

            size = (int)(&(lptr[1]) - &(lptr[0]));
            for (i = 2 * maxdeg; i >= 0; i--)
            {
                if (bucket[i] != null)
                {
                    Console.Write("  Bucket {0:d}:", i - maxdeg);
                    for (bptr = bucket[i]; bptr != null; bptr = bptr->next)
                    {
                        val = ((int)(bptr - lptr)) / size;
                        Console.Write(" {0:d}", val);
                    }

                    Console.WriteLine();
                }
            }
        }
예제 #3
0
/*static void p1bucket();*/

        private static void pbuckets(bilist ****buckets, /* pointers to bucket lists */
                                     bilist **listspace, /* elements within buckets */
                                     int maxdeg,         /* maximum degree of a vertex */
                                     int nsets           /* number of sets being divided into */
                                     )
        {
            bilist *lptr; /* points to correct listspace */
            int     i, j; /* loop counter */

            Console.WriteLine();
            for (i = 0; i < nsets; i++)
            {
                for (j = 0; j < nsets; j++)
                {
                    if (i != j)
                    {
                        Console.WriteLine("For transition {0:d} -> {1:d}", i, j);
                        if (j > i)
                        {
                            lptr = listspace[j - 1];
                        }
                        else
                        {
                            lptr = listspace[j];
                        }
                        p1bucket(buckets[i][j], lptr, maxdeg);
                        Console.WriteLine();
                    }
                }
            }
            Console.WriteLine();
        }
예제 #4
0
        public static void movebilist(bilist *lptr,     /* ptr to element to move */
                                      bilist **oldlist, /* head of list to remove it from */
                                      bilist **newlist  /* head of list to add it to */
                                      )

/* Move an element from a old bidirectional list to new one. */
        {
            removebilist(lptr, oldlist);

            add2bilist(lptr, newlist);
        }
예제 #5
0
/* Note: bi-directional lists aren't assumed to be sorted. */
        private static void add2bilist( /* add val to unsorted list */
            bilist *lptr,               /* element to add */
            bilist **list               /* list added to */
            )
        {
            lptr->next = *list;
            if (*list != null)
            {
                (*list)->prev = lptr;
            }
            lptr->prev = null;
            *list = lptr;
        }
예제 #6
0
        static void free_kl(
            /* Free everything malloc'd for KL. */
            bilist ****buckets, /* space for bucket sorts */
            bilist **listspace, /* space for all bidirectional elements */
            int **dvals,        /* change in penalty for each possible move */
            int **tops          /* starting dval for each type of move */
            )
        {
            Marshal.FreeHGlobal((IntPtr)dvals);
            Marshal.FreeHGlobal((IntPtr)tops);

            Marshal.FreeHGlobal((IntPtr)listspace[0]);
            Marshal.FreeHGlobal((IntPtr)buckets[0][1]);
            Marshal.FreeHGlobal((IntPtr)listspace);
            Marshal.FreeHGlobal((IntPtr)buckets);
        }
예제 #7
0
 public static void free_klv(
     /* Free everything malloc'd for KLV. */
     bilist **lbuckets,  /* space for bucket sorts */
     bilist **rbuckets,  /* space for bucket sorts */
     bilist *llistspace, /* space for all bidirectional elements */
     bilist *rlistspace, /* space for all bidirectional elements */
     int *ldvals,        /* change in penalty for each possible move */
     int *rdvals         /* change in penalty for each possible move */
     )
 {
     Marshal.FreeHGlobal((IntPtr)rlistspace);
     Marshal.FreeHGlobal((IntPtr)llistspace);
     Marshal.FreeHGlobal((IntPtr)rdvals);
     Marshal.FreeHGlobal((IntPtr)ldvals);
     Marshal.FreeHGlobal((IntPtr)rbuckets);
     Marshal.FreeHGlobal((IntPtr)lbuckets);
 }
예제 #8
0
        private static void removebilist(bilist *lptr, /* ptr to element to remove */
                                         bilist **list /* head of list to remove it from */
                                         )

/* Remove an element from a bidirectional list. */
        {
            if (lptr->next != null)
            {
                lptr->next->prev = lptr->prev;
            }
            if (lptr->prev != null)
            {
                lptr->prev->next = lptr->next;
            }
            else
            {
                *list = lptr->next;
            }
        }
예제 #9
0
/* Idea:
 * 'buckets[i][j]' is a set of buckets to sort moves from i to j.
 * listspace[i] is space for lists in buckets[i][j].
 * Loop through all nonequal pairs [i][j], taking the first element
 * in each list.  Compare them all to find the largest allowed move.
 * Make that move, and save it in movelist.
 */

        public static void bucketsort1(vtx_data **graph,              /* graph data structure */
                                       int vtx,                       /* vertex being added to lists */
                                       bilist ****buckets,            /* array of lists for bucket sort */
                                       bilist **listspace,            /* list data structure for each vertex */
                                       int **dvals,                   /* d-values for each vertex for removing */
                                       int *sets,                     /* processor each vertex is assigned to */
                                       float *[]           term_wgts, /* weights for terminal propagation */
                                       int maxdval,                   /* maximum possible dvalue for a vertex */
                                       int nsets,                     /* number of sets being divided into */
                                       int [][] hops,                 /* hop cost between sets */
                                       bool useEdgeWeights            /* are edge weights being used? */
                                       )
        {
            bilist *lptr  = null; /* pointer to an element in listspace */
            float * ewptr = null; /* loops through edge weights */
            int *   edges = null; /* edge list for a vertex */
            int     myset;        /* set that current vertex belongs to */
            int     newset;       /* set current vertex could move to */
            int     set;          /* set that neighboring vertex belongs to */
            int     weight;       /* edge weight for a particular edge */
            float   tval;         /* terminal propagation value */
            int     val;          /* terminal propagation rounded value */
            double  cut_cost;     /* relative cut/hop importance */
            double  hop_cost;     /* relative hop/cut importance */
            int     myhop;        /* hops associated with current vertex */
            int     j, l;         /* loop counters */

            /* Compute d-vals by seeing which sets neighbors belong to. */
            cut_cost = hop_cost = 1;
            if (term_wgts[1] != null)
            {
                if (CUT_TO_HOP_COST > 1)
                {
                    cut_cost = CUT_TO_HOP_COST;
                }
                else
                {
                    hop_cost = 1.0 / CUT_TO_HOP_COST;
                }
            }

            weight = (int)(cut_cost + .5);
            myset  = sets[vtx];

            /* Initialize all the preference values. */
            if (term_wgts[1] != null)
            {
                /* Using terminal propagation. */
                if (myset == 0) /* No terminal value. */
                {
                    for (newset = 1; newset < nsets; newset++)
                    {
                        tval = (term_wgts[newset])[vtx];
                        if (tval < 0)
                        {
                            val = (int)(-tval * hop_cost + .5);
                            val = -val;
                        }
                        else
                        {
                            val = (int)(tval * hop_cost + .5);
                        }
                        dvals[vtx][newset - 1] = val;
                    }
                }
                else
                {
                    tval = -(term_wgts[myset])[vtx];
                    if (tval < 0)
                    {
                        val = (int)(-tval * hop_cost + .5);
                        val = -val;
                    }
                    else
                    {
                        val = (int)(tval * hop_cost + .5);
                    }
                    dvals[vtx][0] = val;
                    l             = 1;
                    for (newset = 1; newset < nsets; newset++)
                    {
                        if (newset != myset)
                        {
                            tval = (term_wgts[newset])[vtx] - (term_wgts[myset])[vtx];
                            if (tval < 0)
                            {
                                val = (int)(-tval * hop_cost + .5);
                                val = -val;
                            }
                            else
                            {
                                val = (int)(tval * hop_cost + .5);
                            }
                            dvals[vtx][l] = val;
                            l++;
                        }
                    }
                }
            }
            else
            {
                for (j = 0; j < nsets - 1; j++)
                {
                    dvals[vtx][j] = 0;
                }
            }

            /* First count the neighbors in each set. */
            edges = graph[vtx]->edges;
            if (useEdgeWeights)
            {
                ewptr = graph[vtx]->ewgts;
            }
            for (j = graph[vtx]->nedges - 1; j != 0; j--)
            {
                set = sets[*(++edges)];
                if (set < 0)
                {
                    set = -set - 1;
                }
                if (useEdgeWeights)
                {
                    weight = (int)(*(++ewptr) * cut_cost + .5);
                }
                myhop = hops[myset][set];

                l = 0;
                for (newset = 0; newset < nsets; newset++)
                {
                    if (newset != myset)
                    {
                        dvals[vtx][l] += weight * (myhop - hops[newset][set]);
                        l++;
                    }
                }
            }

            /* Now add to appropriate buckets. */
            l = 0;
            for (newset = 0; newset < nsets; newset++)
            {
                if (newset != myset)
                {
                    lptr = listspace[l];
                    add2bilist(&lptr[vtx], &buckets[myset][newset][dvals[vtx][l] + maxdval]);
                    ++l;
                }
            }
        }
예제 #10
0
        /* Idea:
         * 'buckets[i][j]' is a set of buckets to sort moves from i to j.
         * listspace[i] is space for lists in buckets[i][j].
         * Loop through all nonequal pairs [i][j], taking the first element
         * in each list.  Compare them all to find the largest allowed move.
         * Make that move, and save it in movelist.
         */

/* Routine slightly streamlined for case with only two sets. */

        public static void bucketsorts_bi(vtx_data **graph,              /* graph data structure */
                                          int nvtxs,                     /* number of vertices */
                                          bilist ****buckets,            /* array of lists for bucket sort */
                                          bilist **listspace,            /* list data structure for each vertex */
                                          int **dvals,                   /* d-values for each vertex for removing */
                                          int *sets,                     /* processor each vertex is assigned to */
                                          float *[]           term_wgts, /* weights for terminal propagation */
                                          int maxdval,                   /* maximum possible dvalue for a vertex */
                                          int nsets,                     /* number of sets being divided into */
                                          bool parity,                   /* work in forward or backward direction? */
                                          int [][] hops,                 /* hop cost between sets */
                                          int *bspace,                   /* indices for randomly ordering vtxs */
                                          int list_length,               /* number of values in bspace to work with */
                                          int npass,                     /* which pass through KL is this? */
                                          bool useEdgeWeights            /* are edge weights being used? */
                                          )
        {
            bilist **bptr  = null; /* loops through set of buckets */
            bilist * lptr  = null; /* pointer to an element in listspace */
            float *  ewptr = null; /* loops through edge weights */
            float *  twptr = null; /* weights for terminal propagation */
            int *    bsptr = null; /* loops through bspace */
            int *    edges = null; /* edge list for a vertex */
            int      myset;        /* set current vertex belongs to */
            int      other_set;    /* set current vertex doesn't belong to */
            int      set;          /* set that neighboring vertex belongs to */
            int      weight;       /* edge weight for a particular edge */
            int      vtx;          /* vertex in graph */
            int      val;          /* terminal propagation rounded value */
            double   cut_cost;     /* relative cut/hop importance */
            double   hop_cost;     /* relative hop/cut importance */
            int      myhop;        /* hops associated with current vertex */
            int      i, j;         /* loop counters */

            /* For each vertex, compute d-values for each possible transition. */
            /* Then store them in each appropriate bucket. */

            if (npass == 1 || !KL_UNDO_LIST || list_length == nvtxs)
            {
                /* Empty all the buckets. */
                /* Last clause catches case where lists weren't undone. */
                bptr = buckets[0][1];
                for (i = nsets * (nsets - 1) * (2 * maxdval + 1); i != 0; i--)
                {
                    *bptr++ = null;
                }
            }

            /* Randomize the order of the vertices */

            if ((KL_UNDO_LIST && list_length == nvtxs) || !KL_UNDO_LIST)
            {
                list_length = nvtxs;
                bsptr       = bspace;
                if (parity)
                {
                    for (i = 1; i <= nvtxs; i++)
                    {
                        *bsptr++ = i;
                    }
                }
                else
                {
                    for (i = nvtxs; i != 0; i--)
                    {
                        *bsptr++ = i;
                    }
                }
            }
            if (KL_RANDOM)
            {
                randomize(bspace - 1, list_length);
            }

            /* Now compute d-vals by seeing which sets neighbors belong to. */
            cut_cost = hop_cost = 1;
            if (term_wgts[1] != null)
            {
                if (CUT_TO_HOP_COST > 1)
                {
                    cut_cost = CUT_TO_HOP_COST;
                }
                else
                {
                    hop_cost = 1.0 / CUT_TO_HOP_COST;
                }
            }

            weight = (int)(cut_cost + .5);

            bsptr = bspace;
            twptr = term_wgts[1];
            for (i = 0; i < list_length; i++) /* Loop through vertices. */
            {
                vtx       = *bsptr++;
                myset     = sets[vtx];
                other_set = myset == 0 ? 1 : 0;

                /* Initialize all the preference values. */
                if (twptr != null)
                {
                    /* Using terminal propagation.  Round to integer value. */
                    if (twptr[vtx] < 0)
                    {
                        val = (int)(-twptr[vtx] * hop_cost + .5);
                        val = -val;
                    }
                    else
                    {
                        val = (int)(twptr[vtx] * hop_cost + .5);
                    }
                    if (myset == 0)
                    {
                        dvals[vtx][0] = val;
                    }
                    else
                    {
                        dvals[vtx][0] = -val;
                    }
                }
                else
                {
                    dvals[vtx][0] = 0;
                }

                /* First count the neighbors in each set. */
                edges = graph[vtx]->edges;
                if (useEdgeWeights)
                {
                    ewptr = graph[vtx]->ewgts;
                }
                for (j = graph[vtx]->nedges - 1; j != 0; j--)
                {
                    set = sets[*(++edges)];
                    if (set < 0)
                    {
                        set = -set - 1;
                    }
                    if (useEdgeWeights)
                    {
                        weight = (int)((*(++ewptr)) * cut_cost + .5);
                    }
                    myhop = hops[myset][set];

                    dvals[vtx][0] += weight * (myhop - hops[other_set][set]);
                }

                /* Now add to appropriate buckets. */
                lptr = listspace[0];
                add2bilist(&lptr[vtx], &buckets[myset][other_set][dvals[vtx][0] + maxdval]);
            }
        }
예제 #11
0
        public static void bucketsortsv(vtx_data **graph,   /* graph data structure */
                                        int nvtxs,          /* number of vertices */
                                        bilist **lbuckets,  /* array of lists for bucket sort */
                                        bilist **rbuckets,  /* array of lists for bucket sort */
                                        bilist *llistspace, /* list data structure for each vertex */
                                        bilist *rlistspace, /* list data structure for each vertex */
                                        int *ldvals,        /* d-values for each vertex for removing */
                                        int *rdvals,        /* d-values for each vertex for removing */
                                        int *sets,          /* processor each vertex is assigned to */
                                        int maxdval,        /* maximum possible dvalue for a vertex */
                                        bool parity,        /* work in forward or backward direction? */
                                        int *bspace,        /* indices for randomly ordering vtxs */
                                        int list_length     /* number of values in bspace to work with */
                                        )
        {
            bilist **lbptr;        /* loops through set of buckets */
            bilist **rbptr;        /* loops through set of buckets */
            int *    bsptr;        /* loops through bspace */
            int *    edges;        /* edge list for a vertex */
            int      left_weight;  /* my neighbors in 0 set */
            int      right_weight; /* my neighbors in 1 set */
            int      vtx;          /* vertex in graph */
            int      neighbor;     /* neighbor of vertex */
            int      set;          /* set that neighboring vertex belongs to */
            int      i, j;         /* loop counters */

            /* For each vertex, compute d-values and store in buckets. */

            /* Empty all the buckets. */
            rbptr = lbuckets;
            lbptr = rbuckets;
            for (i = (2 * maxdval + 1); i != 0; i--)
            {
                *lbptr++ = null;
                *rbptr++ = null;
            }

            /* Randomize the order of the vertices */

            if ((KL_UNDO_LIST && list_length == nvtxs) || (!KL_UNDO_LIST && !KL_RANDOM) || list_length == 0)
            {
                /* Don't need to reoder if about to randomize. */
                list_length = nvtxs;
                bsptr       = bspace;
                if (parity)
                {
                    for (i = 1; i <= nvtxs; i++)
                    {
                        *bsptr++ = i;
                    }
                }
                else
                {
                    for (i = nvtxs; i != 0; i--)
                    {
                        *bsptr++ = i;
                    }
                }
            }

            if (KL_RANDOM)
            {
                randomize(bspace - 1, list_length);
            }

            /* Now compute d-vals by seeing which sets neighbors belong to. */

            bsptr = bspace;
            for (i = 0; i < list_length; i++)
            {
                /* Loop through vertices. */
                vtx = *bsptr++;
                if (sets[vtx] == 2)
                {
                    /* Only worry about separator vertices. */

                    /* Initialize all the preference values. */
                    left_weight = right_weight = 0;

                    /* First count the neighbors in each set. */
                    edges = graph[vtx]->edges;
                    for (j = graph[vtx]->nedges - 1; j != 0; j--)
                    {
                        neighbor = *(++edges);
                        set      = sets[neighbor];
                        if (set < 0)
                        {
                            set = -set - 1;
                        }

                        if (set == 0)
                        {
                            left_weight += graph[neighbor]->vwgt;
                        }
                        else if (set == 1)
                        {
                            right_weight += graph[neighbor]->vwgt;
                        }
                    }

                    ldvals[vtx] = graph[vtx]->vwgt - right_weight;
                    rdvals[vtx] = graph[vtx]->vwgt - left_weight;

                    /* Now add to appropriate buckets. */
                    add2bilist(&llistspace[vtx], &lbuckets[ldvals[vtx] + maxdval]);
                    add2bilist(&rlistspace[vtx], &rbuckets[rdvals[vtx] + maxdval]);
                }
            }
        }
예제 #12
0
        public static void make_bndy_list(vtx_data **graph,   /* data structure for graph */
                                          bilist *movelist,   /* list of vtxs to be moved */
                                          bilist ****buckets, /* array of lists for bucket sort */
                                          bilist **listspace, /* list data structure for each vertex */
                                          int *sets,          /* processor each vertex is assigned to */
                                          int nsets,          /* number of sets divided into */
                                          int *bspace,        /* list of active vertices for bucketsort */
                                          int **tops,         /* top of each set of buckets */
                                          int **bndy_list     /* list of boundary vertices returned */
                                          )
        {
            bilist *bptr;        /* loops through bspace */
            int     vtx;         /* vertex that was moved */
            int     set;         /* set a vertex is in */
            int     list_length; /* number of active vertices */
            int     bndy_length; /* number of vertices actually on boundary */
            int     size;        /* array spacing */
            int     i, j, k;     /* loop counters */

            /* First push all the moved vertices onto list, so they can be flagged. */
            /* They've already been removed from buckets, so want to avoid them. */
            size        = (int)(&(listspace[0][1]) - &(listspace[0][0]));
            bptr        = movelist;
            list_length = 0;
            while (bptr != null)
            {
                vtx = ((int)(bptr - listspace[0])) / size;
                bspace[list_length++] = vtx;
                bptr = bptr->next;
            }

            /* Now get all the vertices still in the bucket lists. */
            for (k = tops[0][1]; k >= 0; k--)
            {
                bptr = buckets[0][1][k];
                while (bptr != null)
                {
                    vtx = ((int)(bptr - listspace[0])) / size;
                    bspace[list_length++] = vtx;
                    bptr = bptr->next;
                }
            }

            for (i = 1; i < nsets; i++)
            {
                for (k = tops[i][0]; k >= 0; k--)
                {
                    bptr = buckets[i][0][k];
                    while (bptr != null)
                    {
                        vtx = ((int)(bptr - listspace[0])) / size;
                        bspace[list_length++] = vtx;
                        bptr = bptr->next;
                    }
                }
            }

            /* Now that list is constructed, go reconstruct all the set numbers. */
            bndy_length = 0;
            for (i = 0; i < list_length; i++)
            {
                vtx = bspace[i];
                set = sets[vtx];
                for (j = 1; j < graph[vtx]->nedges; j++)
                {
                    if (sets[graph[vtx]->edges[j]] != set)
                    {
                        bspace[bndy_length++] = vtx;
                        break;
                    }
                }
            }

            /* Finally, copy boundary vertices into boundary list. */
            *bndy_list = (int *)Marshal.AllocHGlobal((bndy_length + 1) * sizeof(int));
            for (i = 0; i < bndy_length; i++)
            {
                (*bndy_list)[i] = bspace[i];
            }

            (*bndy_list)[bndy_length] = 0;
        }
예제 #13
0
 private static void p1bucket(bilist **a, bilist *b, int c)
 {
     throw new NotImplementedException("I couldn't find the implementation for this in Chaco source.");
 }
예제 #14
0
        /*
         * Keep guys moved in and guys moving out of separator.
         * To restore, move all undesirable guys back.
         * (1) guys moved out of separator get put back in.
         * (2) guys moved into separator (bspace) get put back.
         * Note: Should be done in this order.
         * Note: No neighbors need be considered.
         * (3) To clear dvals, I should compute touch all guys that
         * were ever in separator (bspace) and their neighbors.
         */

        public static bool nway_klv(vtx_data **graph,   /* data structure for graph */
                                    int nvtxs,          /* number of vtxs in graph */
                                    bilist **lbuckets,  /* array of lists for bucket sort */
                                    bilist **rbuckets,  /* array of lists for bucket sort */
                                    bilist *llistspace, /* list data structure for each vertex */
                                    bilist *rlistspace, /* list data structure for each vertex */
                                    int *ldvals,        /* d-values for each transition */
                                    int *rdvals,        /* d-values for each transition */
                                    int *sets,          /* processor each vertex is assigned to */
                                    int maxdval,        /* maximum d-value for a vertex */
                                    double[] goal,      /* desired set sizes */
                                    int max_dev,        /* largest allowed deviation from balance */
                                    int **bndy_list,    /* list of vertices on boundary (0 ends) */
                                    double[] weightsum  /* sum of vweights in each set (in and out) */
                                    )
        {
            bilist **to_buckets;           /* buckets I'm moving to */
            bilist **from_buckets;         /* buckets I'm moving from */
            bilist * to_listspace;         /* list structure I'm moving to */
            bilist * from_listspace;       /* list structure I'm moving from */
            bilist * out_list;             /* list of vtxs moved out of separator */
            int *    to_dvals;             /* d-values I'm moving to */
            int *    from_dvals;           /* d-values I'm moving from */
            int *    bspace;               /* list of active vertices for bucketsort */
            int *    edges;                /* edge list for a vertex */
            int *    edges2;               /* edge list for a vertex */
            int *    bdy_ptr;              /* loops through bndy_list */
            double   total_weight;         /* weight of all vertices */
            double   partial_weight;       /* weight of vertices not in separator */
            double   ratio;                /* fraction of weight not in separator */
            double   time;                 /* timing parameter */
            double   delta0;               /* largest negative deviation from goal size */
            double   delta1;               /* largest negative deviation from goal size */
            double   left_imbalance = 0.0; /* imbalance if I move to the left */
            double   right_imbalance;      /* imbalance if I move to the right */
            double   balance_val;          /* how imbalanced is it */
            double   balance_best;         /* best balance yet if trying hard */
            bool     flag;                 /* condition indicator */
            int      to = -1, from;        /* sets moving into / out of */
            int      rtop, ltop;           /* top of each set of buckets */
            int *    to_top;               /* ptr to top of set moving to */
            int      lvtx, rvtx;           /* next vertex to move left/right */
            int      lweight, rweight;     /* weights of moving vertices */
            int      weightfrom = 0;       /* weight moving out of a set */
            int      list_length;          /* how long is list of vertices to bucketsort? */
            bool     balanced;             /* is partition balanced? */
            bool     temp_balanced;        /* is intermediate partition balanced? */
            bool     ever_balanced;        /* has any partition been balanced? */
            int      bestvtx = -1;         /* best vertex to move */
            int      bestval = -1;         /* best change in value for a vtx move */
            int      vweight;              /* weight of best vertex */
            int      gtotal;               /* sum of changes from moving */
            int      improved;             /* total improvement from KL */
            double   bestg;                /* maximum gtotal found in KL loop */
            double   bestg_min;            /* smaller than any possible bestg */
            int      beststep;             /* step where maximum value occurred */
            int      bestlength;           /* step where maximum value occurred */
            int      neighbor;             /* neighbor of a vertex */
            int      step_cutoff;          /* number of negative steps in a row allowed */
            int      cost_cutoff;          /* amount of negative d-values allowed */
            int      neg_steps;            /* number of negative steps in a row */
            int      neg_cost;             /* decrease in sum of d-values */
            int      vtx;                  /* vertex number */
            int      dval;                 /* dval of a vertex */
            int      group, group2;        /* set that a vertex is assigned to */
            bool     left_too_big;         /* is left set too large? */
            bool     right_too_big;        /* is right set too large? */
            int      vwgt;                 /* weight of a vertex */
            int      gain;                 /* reduction in separator due to a move */
            int      neighbor2;            /* neighbor of a vertex */
            int      step;                 /* loops through movements of vertices */
            bool     parity;               /* sort forwards or backwards? */
            bool     done;                 /* has termination criteria been achieved? */
            int      nbad;                 /* number of unhelpful passes in a row */
            int      npass;                /* total number of passes */
            int      nbadtries;            /* number of unhelpful passes before quitting */
            bool     enforce_balance;      /* force a balanced partition? */
            bool     enforce_balance_hard; /* really force a balanced partition? */
            int      i, j, k;              /* loop counters */

            nbadtries = KL_NTRIES_BAD;

            enforce_balance      = false;
            enforce_balance_hard = false;

            total_weight = goal[0] + goal[1];

            bspace = (int *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(int));

            if (bspace == null)
            {
                return(true);
            }

            bdy_ptr     = *bndy_list;
            list_length = 0;
            while (*bdy_ptr != 0)
            {
                bspace[list_length++] = *bdy_ptr++;
            }

            Marshal.FreeHGlobal((IntPtr)(*bndy_list));

            clear_dvals(graph, nvtxs, ldvals, rdvals, bspace, list_length);

            step_cutoff = KL_BAD_MOVES;
            cost_cutoff = maxdval * step_cutoff / 7;
            if (cost_cutoff < step_cutoff)
            {
                cost_cutoff = step_cutoff;
            }

            partial_weight = weightsum[0] + weightsum[1];
            ratio          = partial_weight / total_weight;
            delta0         = Math.Abs(weightsum[0] - goal[0] * ratio);
            delta1         = Math.Abs(weightsum[1] - goal[1] * ratio);
            balanced       =
                (delta0 + delta1 <= max_dev) && weightsum[0] != total_weight && weightsum[1] != total_weight;

            bestg_min = -2.0 * nvtxs * maxdval;
            parity    = false;
            nbad      = 0;
            npass     = 0;
            improved  = 0;
            done      = false;
            while (!done)
            {
                npass++;
                ever_balanced = false;
                balance_best  = delta0 + delta1;

                /* Initialize various quantities. */
                ltop = rtop = 2 * maxdval;

                gtotal     = 0;
                bestg      = bestg_min;
                beststep   = -1;
                bestlength = list_length;
                out_list   = null;

                neg_steps = 0;

                /* Compute the initial d-values, and bucket-sort them. */
                time = seconds();
                bucketsortsv(graph, nvtxs, lbuckets, rbuckets, llistspace, rlistspace, ldvals, rdvals, sets,
                             maxdval, parity, bspace, list_length);
                parity          = !parity;
                kl_bucket_time += seconds() - time;

                if (DEBUG_KL == DebugFlagKL.PrintBucket)
                {
                    Console.WriteLine("After sorting, left buckets:");
                    p1bucket(lbuckets, llistspace, maxdval);
                    Console.WriteLine("              right buckets:");
                    p1bucket(rbuckets, rlistspace, maxdval);
                }

                /* Now determine the set of vertex moves. */

                for (step = 1;; step++)
                {
                    /* Find the highest d-value in each set. */
                    /* But only consider moves from large to small sets, or moves */
                    /* in which balance is preserved. */
                    /* Break ties in some nonarbitrary manner. */
                    bestval = -maxdval - 1;

                    partial_weight = weightsum[0] + weightsum[1];
                    ratio          = partial_weight / total_weight;
                    left_too_big   = (weightsum[0] > (goal[0] + .5 * max_dev) * ratio);
                    right_too_big  = (weightsum[1] > (goal[1] + .5 * max_dev) * ratio);

                    while (ltop >= 0 && lbuckets[ltop] == null)
                    {
                        --ltop;
                    }

                    if (ltop >= 0 && !left_too_big)
                    {
                        lvtx           = (int)(((long)lbuckets[ltop] - (long)llistspace) / sizeof(bilist));
                        lweight        = graph[lvtx]->vwgt;
                        rweight        = lweight - (ltop - maxdval);
                        weightfrom     = rweight;
                        to             = 0;
                        bestvtx        = lvtx;
                        bestval        = ltop - maxdval;
                        partial_weight = weightsum[0] + lweight + weightsum[1] - rweight;
                        ratio          = partial_weight / total_weight;
                        left_imbalance = Math.Max(Math.Abs(weightsum[0] + lweight - goal[0] * ratio),
                                                  Math.Abs(weightsum[1] - rweight - goal[1] * ratio));
                    }

                    while (rtop >= 0 && rbuckets[rtop] == null)
                    {
                        --rtop;
                    }

                    if (rtop >= 0 && !right_too_big)
                    {
                        rvtx            = (int)(((long)rbuckets[rtop] - (long)rlistspace) / sizeof(bilist));
                        rweight         = graph[rvtx]->vwgt;
                        lweight         = rweight - (rtop - maxdval);
                        partial_weight  = weightsum[0] - lweight + weightsum[1] + rweight;
                        ratio           = partial_weight / total_weight;
                        right_imbalance = Math.Max(Math.Abs(weightsum[0] - lweight - goal[0] * ratio),
                                                   Math.Abs(weightsum[1] + rweight - goal[1] * ratio));
                        if (rtop - maxdval > bestval || (rtop - maxdval == bestval &&
                                                         (right_imbalance < left_imbalance ||
                                                          (right_imbalance == left_imbalance && drandom() < .5))))
                        {
                            to         = 1;
                            weightfrom = lweight;
                            bestvtx    = rvtx;
                            bestval    = rtop - maxdval;
                        }
                    }

                    if (bestval == -maxdval - 1)
                    {
                        /* No allowed moves */
                        if (DEBUG_KL != DebugFlagKL.NoDebugging)
                        {
                            Console.WriteLine("No KLV moves at step {0:d}.  bestg = {1:g} at step {2:d}.", step, bestg, beststep);
                        }

                        break;
                    }

                    if (to == 0)
                    {
                        from           = 1;
                        to_listspace   = llistspace;
                        from_listspace = rlistspace;
                        to_dvals       = ldvals;
                        from_dvals     = rdvals;
                        to_buckets     = lbuckets;
                        from_buckets   = rbuckets;
                        to_top         = &ltop;
                    }
                    else
                    {
                        from           = 0;
                        to_listspace   = rlistspace;
                        from_listspace = llistspace;
                        to_dvals       = rdvals;
                        from_dvals     = ldvals;
                        to_buckets     = rbuckets;
                        from_buckets   = lbuckets;
                        to_top         = &rtop;
                    }

                    vweight = graph[bestvtx]->vwgt;

                    weightsum[to]   += vweight;
                    weightsum[from] -= weightfrom;

                    /* Check if this partition is balanced. */
                    partial_weight = weightsum[0] + weightsum[1];
                    ratio          = partial_weight / total_weight;
                    delta0         = Math.Abs(weightsum[0] - goal[0] * ratio);
                    delta1         = Math.Abs(weightsum[1] - goal[1] * ratio);
                    temp_balanced  = (delta0 + delta1 <= max_dev) && weightsum[0] != total_weight &&
                                     weightsum[1] != total_weight;
                    ever_balanced = (ever_balanced || temp_balanced);
                    balance_val   = delta0 + delta1;

                    gtotal += bestval;

                    if ((gtotal > bestg && temp_balanced) ||
                        (enforce_balance_hard && balance_val < balance_best))
                    {
                        bestg    = gtotal;
                        beststep = step;
                        if (balance_val < balance_best)
                        {
                            balance_best = balance_val;
                        }

                        if (temp_balanced)
                        {
                            enforce_balance_hard = false;
                        }
                    }

                    if (DEBUG_KL == DebugFlagKL.MoreInfo || DEBUG_KL == DebugFlagKL.PrintBucket)
                    {
                        Console.WriteLine("At KLV step {0:d}, bestvtx={1:d}, bestval={2:d} (2->{3:d}), wt0 = {4:g,} wt1 = {5:g}", step, bestvtx, bestval, to, weightsum[0], weightsum[1]);
                    }

                    /* Monitor the stopping criteria. */
                    if (bestval < 0)
                    {
                        if (!enforce_balance || ever_balanced)
                        {
                            neg_steps++;
                        }

                        if (bestg != bestg_min)
                        {
                            neg_cost = (int)bestg - gtotal;
                        }
                        else
                        {
                            neg_cost = -maxdval - 1;
                        }

                        if ((neg_steps > step_cutoff || neg_cost > cost_cutoff) &&
                            !(enforce_balance && bestg == bestg_min))
                        {
                            if (DEBUG_KL != DebugFlagKL.NoDebugging)
                            {
                                if (neg_steps > step_cutoff || neg_cost > cost_cutoff)
                                {
                                    Console.WriteLine("KLV step cutoff at step {0:d}.  bestg = {1:g} at step {2:d}.", step, bestg, beststep);
                                }
                            }

                            weightsum[to]   -= vweight;
                            weightsum[from] += weightfrom;
                            break;
                        }
                    }
                    else if (bestval > 0)
                    {
                        neg_steps = 0;
                    }

                    /* Remove vertex from its buckets, and flag it as finished. */
                    sets[bestvtx] = to;
                    removebilist(&to_listspace[bestvtx], &to_buckets[bestval + maxdval]);

                    /*
                     *          printf("After to removebilist\n");
                     *          p1bucket(to_buckets, to_listspace, maxdval);
                     */

                    if (from_dvals[bestvtx] != -maxdval - 1)
                    {
                        removebilist(&from_listspace[bestvtx], &from_buckets[from_dvals[bestvtx] + maxdval]);

                        /*
                         *              printf("After from removebilist\n");
                         *              p1bucket(from_buckets, from_listspace, maxdval);
                         */
                    }

                    from_dvals[bestvtx] = -maxdval - 1;

                    /* Now keep track of vertices moved out of separator so */
                    /* I can restore them as needed. */
                    llistspace[bestvtx].next = out_list;
                    out_list = &(llistspace[bestvtx]);

                    /* Now update the d-values of all the neighbors */
                    /* And neighbors of neighbors ... */

                    /* If left move:
                     * 1. Separator neighbors right gain => infinity
                     * 2. Left neighbors unaffected.
                     * 3. Right neighbors move into separator.
                     *    A. Right gain = infinity.
                     *    B. Left gain = computed.
                     *    C. For any of their neighbors in separator increase left gain.
                     */

                    edges = graph[bestvtx]->edges;
                    for (j = graph[bestvtx]->nedges - 1; j != 0; j--)
                    {
                        neighbor = *(++edges);

                        group = sets[neighbor];

                        if (group == 2)
                        {
                            /* In separator. */
                            gain = from_dvals[neighbor] + maxdval;
                            /* Gain in the from direction => -infinity */
                            if (gain >= 0)
                            {
                                removebilist(&from_listspace[neighbor], &from_buckets[gain]);

                                /*
                                 *                      printf("\n  After removing %d\n", neighbor);
                                 *                      p1bucket(from_buckets, from_listspace, maxdval);
                                 */
                                from_dvals[neighbor] = -maxdval - 1;
                            }
                        }
                        else if (group == from)
                        {
                            /* Gain in the from direction => -infinity */
                            sets[neighbor]       = 2;
                            from_dvals[neighbor] = -maxdval - 1;

                            if (to == 0)
                            {
                                bspace[list_length++] = -neighbor;
                            }
                            else
                            {
                                bspace[list_length++] = neighbor;
                            }

                            edges2 = graph[neighbor]->edges;
                            vwgt   = graph[neighbor]->vwgt;
                            gain   = graph[neighbor]->vwgt;
                            flag   = false;
                            for (k = graph[neighbor]->nedges - 1; k != 0; k--)
                            {
                                neighbor2 = *(++edges2);
                                group2    = sets[neighbor2];
                                if (group2 == 2)
                                {
                                    dval = to_dvals[neighbor2] + maxdval;
                                    if (dval >= 0)
                                    {
                                        movebilist(&to_listspace[neighbor2], &to_buckets[dval], &to_buckets[dval + vwgt]);

                                        /*
                                         *                              printf("\n  After moving %d from bucket %d to bucket
                                         * %d\n", neighbor2, dval, dval + vwgt);
                                         *                              p1bucket(to_buckets, to_listspace, maxdval);
                                         */
                                        to_dvals[neighbor2] += vwgt;
                                        dval += vwgt;
                                        if (dval > *to_top)
                                        {
                                            *to_top = dval;
                                        }
                                    }
                                }
                                else if (group2 == from)
                                {
                                    gain -= graph[neighbor2]->vwgt;
                                    if (to_dvals[neighbor2] + maxdval < 0)
                                    {
                                        flag = true;
                                    }
                                }
                            }

                            if (flag)
                            {
                                /* Not allowed to move further. */
                                to_dvals[neighbor] = -maxdval - 1;
                            }
                            else
                            {
                                to_dvals[neighbor] = gain;
                                /* place in appropriate bucket */

                                gain += maxdval;
                                add2bilist(&to_listspace[neighbor], &to_buckets[gain]);

                                /*
                                 *                      printf("\nAfter adding %d to bucket %d\n", neighbor, gain -
                                 * maxdval);
                                 *                      p1bucket(to_buckets, to_listspace, maxdval);
                                 */

                                if (gain > *to_top)
                                {
                                    *to_top = gain;
                                }
                            }
                        }
                    }

                    if (beststep == step)
                    {
                        bestlength = list_length;
                    }

                    if (DEBUG_KL == DebugFlagKL.PrintBucket)
                    {
                        Console.WriteLine("\n-- After step, left buckets:");
                        p1bucket(lbuckets, llistspace, maxdval);
                        Console.WriteLine("             right buckets:");
                        p1bucket(rbuckets, rlistspace, maxdval);
                    }
                }

                /* Done with a pass; should we actually perform any swaps? */
                if (bestg > 0 || (bestg != bestg_min && !balanced && enforce_balance))
                {
                    improved += (int)bestg;
                }
                else
                {
                    if (enforce_balance_hard)
                    {
                        /* I've done the best I can, give up. */
                        done = true;
                    }

                    if (enforce_balance)
                    {
                        enforce_balance_hard = true;
                    }

                    enforce_balance = true;
                    nbad++;
                }

                /* Work backwards, undoing all the undesirable moves. */

                /* First reset vertices moved out of the separator. */
                if (out_list != null)
                {
                    if (beststep < 0)
                    {
                        beststep = 0;
                    }

                    for (i = step - 1; i > beststep; i--)
                    {
                        vtx = (int)(((long)out_list - (long)llistspace) / sizeof(bilist));
                        if (sets[vtx] != 2)
                        {
                            weightsum[sets[vtx]] -= graph[vtx]->vwgt;
                        }

                        sets[vtx] = 2;
                        out_list  = out_list->next;
                    }
                }

                for (i = list_length - 1; i >= bestlength; i--)
                {
                    vtx = bspace[i];
                    if (vtx < 0)
                    {
                        if (sets[-vtx] == 2)
                        {
                            weightsum[1] += graph[-vtx]->vwgt;
                        }

                        sets[-vtx] = 1;
                    }
                    else
                    {
                        if (sets[vtx] == 2)
                        {
                            weightsum[0] += graph[vtx]->vwgt;
                        }

                        sets[vtx] = 0;
                    }
                }

                partial_weight = weightsum[0] + weightsum[1];
                ratio          = partial_weight / total_weight;
                delta0         = Math.Abs(weightsum[0] - goal[0] * ratio);
                delta1         = Math.Abs(weightsum[1] - goal[1] * ratio);
                balanced       = (delta0 + delta1 <= max_dev) && weightsum[0] != total_weight &&
                                 weightsum[1] != total_weight;

                done = done || (nbad >= nbadtries && balanced);
                if (KL_MAX_PASS > 0)
                {
                    done = done || (npass == KL_MAX_PASS && balanced);
                }

                if (!done)
                {
                    /* Rezero dval values. */
                    clear_dvals(graph, nvtxs, ldvals, rdvals, bspace, list_length);
                }

                /* Construct list of separator vertices to pass to buckets or return */
                list_length = make_sep_list(bspace, list_length, sets);

                if (done)
                {
                    bspace[list_length] = 0;
                    bspace = (int *)Marshal.ReAllocHGlobal((IntPtr)bspace, new IntPtr((list_length + 1) * sizeof(int)));
                    *bndy_list = bspace;
                }

                gain = 0;
                j    = k = 0;
                for (i = 1; i <= nvtxs; i++)
                {
                    if (sets[i] == 0)
                    {
                        j += graph[i]->vwgt;
                    }
                    else if (sets[i] == 1)
                    {
                        k += graph[i]->vwgt;
                    }
                    else if (sets[i] == 2)
                    {
                        gain += graph[i]->vwgt;
                    }
                }

                /*
                 *      printf("\nAfter pass of KLV: sets = %d/%d, sep = %d  (bestg = %g)\n\n\n", j, k, gain, bestg);
                 */
            }

            if (DEBUG_KL != DebugFlagKL.NoDebugging)
            {
                Console.WriteLine("   KLV required {0:d} passes to improve by {1:d}.", npass, improved);
            }

            return(false);
        }
예제 #15
0
        private static int make_kl_list(vtx_data **graph,   /* data structure for graph */
                                        bilist *movelist,   /* list of vtxs to be moved */
                                        bilist ****buckets, /* array of lists for bucket sort */
                                        bilist **listspace, /* list data structure for each vertex */
                                        int *sets,          /* processor each vertex is assigned to */
                                        int nsets,          /* number of sets divided into */
                                        int *bspace,        /* list of active vertices for bucketsort */
                                        int **dvals,        /* d-values for each transition */
                                        int maxdval         /* maximum d-value for a vertex */
                                        )
        {
            bilist **list;        /* bucket to erase element from */
            bilist * vptr;        /* loops through movelist */
            int *    bptr;        /* loops through bspace */
            int *    iptr;        /* loops through edge list */
            int      vtx;         /* vertex that was moved */
            int      neighbor;    /* neighbor of a vertex */
            int      myset;       /* set a vertex is in */
            int      newset;      /* loops through other sets */
            int      list_length; /* number of values put in bspace */
            int      size;        /* array spacing */
            int      i, l;        /* loop counter */

            /* First push all the moved vertices onto list, so they can be flagged. */
            /* They've already been removed from buckets, so want to avoid them. */
            size        = (int)(&(listspace[0][1]) - &(listspace[0][0]));
            vptr        = movelist;
            bptr        = bspace;
            list_length = 0;
            while (vptr != null)
            {
                vtx = ((int)(vptr - listspace[0])) / size;
                *bptr++ = vtx;
                if (sets[vtx] >= 0)
                {
                    sets[vtx] = -sets[vtx] - 1;
                }
                ++list_length;
                vptr = vptr->next;
            }

            /* Now look at all the neighbors of moved vertices. */
            vptr = movelist;
            while (vptr != null)
            {
                vtx = ((int)(vptr - listspace[0])) / size;

                iptr = graph[vtx]->edges;
                for (i = graph[vtx]->nedges - 1; i != 0; i--)
                {
                    neighbor = *(++iptr);
                    if (sets[neighbor] >= 0)
                    {
                        *bptr++ = neighbor;
                        ++list_length;
                        myset          = sets[neighbor];
                        sets[neighbor] = -sets[neighbor] - 1;

                        /* Remove neighbor entry from all his buckets. */
                        /* Note: vertices in movelist already removed from buckets. */
                        l = 0;
                        for (newset = 0; newset < nsets; newset++)
                        {
                            if (newset != myset)
                            {
                                list = &buckets[myset][newset][dvals[neighbor][l] + maxdval];
                                removebilist(&listspace[l][neighbor], list);
                                l++;
                            }
                        }
                    }
                }
                vptr = vptr->next;
            }

            /* Now that list is constructed, go reconstruct all the set numbers. */
            bptr = bspace;
            for (i = list_length; i != 0; i--)
            {
                vtx       = *bptr++;
                sets[vtx] = -sets[vtx] - 1;
            }

            return(list_length);
        }
예제 #16
0
        /* Idea:
         * 'buckets[i][j]' is a set of buckets to sort moves from i to j.
         * listspace[i] is space for lists in buckets[i][j].
         * Loop through all nonequal pairs [i][j], taking the first element
         * in each list.  Compare them all to find the largest allowed move.
         * Make that move, and save it in movelist.
         */


        public static bool nway_kl(vtx_data **graph,              /* data structure for graph */
                                   int nvtxs,                     /* number of vtxs in graph */
                                   bilist ****buckets,            /* array of lists for bucket sort */
                                   bilist **listspace,            /* list data structure for each vertex */
                                   int **tops,                    /* 2-D array of top of each set of buckets */
                                   int **dvals,                   /* d-values for each transition */
                                   int *sets,                     /* processor each vertex is assigned to */
                                   int maxdval,                   /* maximum d-value for a vertex */
                                   int nsets,                     /* number of sets divided into */
                                   double []          goal,       /* desired set sizes */
                                   float *[]           term_wgts, /* weights for terminal propagation */
                                   int [][] hops,                 /* cost of set transitions */
                                   int max_dev,                   /* largest allowed deviation from balance */
                                   bool useEdgeWeights,           /* are edge weights being used? */
                                   int **bndy_list,               /* list of vertices on boundary (0 ends) */
                                   double [] startweight          /* sum of vweights in each set (in and out) */
                                   )

/* Suaris and Kedem algorithm for quadrisection, generalized to an */
/* arbitrary number of sets, with intra-set cost function specified by hops. */
/* Note: this is for a single divide step. */
/* Also, sets contains an initial (possibly crummy) partitioning. */

        {
            bilist * movelist;                         /* list of vtxs to be moved */
            bilist **endlist;                          /* end of movelists */
            bilist * bestptr;                          /* best vertex in linked list */
            bilist * bptr;                             /* loops through bucket list */
            float *  ewptr     = null;                 /* loops through edge weights */
            double * locked    = null;                 /* weight of vertices locked in a set */
            double * loose     = null;                 /* weight of vtxs that can move from a set */
            int *    bspace    = null;                 /* list of active vertices for bucketsort */
            double * weightsum = null;                 /* sum of vweights for each partition */
            int *    edges     = null;                 /* edge list for a vertex */
            int *    bdy_ptr   = null;                 /* loops through bndy_list */
            double   time;                             /* timing parameter */
            double   delta;                            /* desire of sets to change size */
            double   bestdelta = -1;                   /* strongest delta value */
            double   deltaplus;                        /* largest negative deviation from goal size */
            double   deltaminus;                       /* largest negative deviation from goal size */
            int      list_length;                      /* how long is list of vertices to bucketsort? */
            bool     balanced;                         /* is partition balanced? */
            bool     temp_balanced;                    /* is intermediate partition balanced? */
            bool     ever_balanced;                    /* has any partition been balanced? */
            int      bestvtx = -1;                     /* best vertex to move */
            int      bestval = -1;                     /* best change in value for a vtx move */
            int      bestfrom = -1, bestto = -1;       /* sets best vertex moves between */
            int      vweight;                          /* weight of best vertex */
            int      gtotal;                           /* sum of changes from moving */
            int      improved;                         /* total improvement from KL */
            double   balance_val = 0.0;                /* how imbalanced is it */
            double   balance_best;                     /* best balance yet if trying hard */
            double   bestg;                            /* maximum gtotal found in KL loop */
            double   bestg_min;                        /* smaller than any possible bestg */
            int      beststep;                         /* step where maximum value occurred */
            int      neighbor;                         /* neighbor of a vertex */
            int      step_cutoff;                      /* number of negative steps in a row allowed */
            int      cost_cutoff;                      /* amount of negative d-values allowed */
            int      neg_steps;                        /* number of negative steps in a row */
            int      neg_cost;                         /* decrease in sum of d-values */
            int      vtx;                              /* vertex number */
            int      dval;                             /* dval of a vertex */
            int      group;                            /* set that a vertex is assigned to */
            double   cut_cost;                         /* if term_prop; relative cut/hop importance */
            int      diff;                             /* change in a d-value */
            int      stuck1st, stuck2nd;               /* how soon will moves be disallowed? */
            int      beststuck1 = -1, beststuck2 = -1; /* best stuck values for tie-breaking */
            int      eweight;                          /* a particular edge weight */
            bool     worth_undoing;                    /* is it worth undoing list? */
            float    undo_frac;                        /* fraction of vtxs indicating worth of undoing */
            int      step;                             /* loops through movements of vertices */
            bool     parity;                           /* sort forwards or backwards? */
            bool     done;                             /* has termination criteria been achieved? */
            int      nbad;                             /* number of unhelpful passes in a row */
            int      npass;                            /* total number of passes */
            int      nbadtries;                        /* number of unhelpful passes before quitting */
            bool     enforce_balance;                  /* force a balanced partition? */
            bool     enforce_balance_hard;             /* really force a balanced partition? */
            bool     balance_trouble;                  /* even balance_hard isn't working */
            int      size;                             /* array spacing */
            int      i, j, k, l;                       /* loop counters */


            nbadtries = KL_NTRIES_BAD;

            enforce_balance      = false;
            temp_balanced        = false;
            enforce_balance_hard = false;
            balance_trouble      = false;

            size = (int)(&(listspace[0][1]) - &(listspace[0][0]));

            undo_frac = 0.3f;

            cut_cost = 1;
            if (term_wgts[1] != null)
            {
                if (CUT_TO_HOP_COST > 1)
                {
                    cut_cost = CUT_TO_HOP_COST;
                }
            }

            bspace    = (int *)Marshal.AllocHGlobal(nvtxs * sizeof(int));
            weightsum = (double *)Marshal.AllocHGlobal(nsets * sizeof(double));
            locked    = (double *)Marshal.AllocHGlobal(nsets * sizeof(double));
            loose     = (double *)Marshal.AllocHGlobal(nsets * sizeof(double));

            if (bspace == null || weightsum == null || locked == null || loose == null)
            {
                Marshal.FreeHGlobal((IntPtr)loose);
                Marshal.FreeHGlobal((IntPtr)locked);
                Marshal.FreeHGlobal((IntPtr)weightsum);
                Marshal.FreeHGlobal((IntPtr)bspace);
                return(true);
            }

            if (*bndy_list != null)
            {
                bdy_ptr     = *bndy_list;
                list_length = 0;
                while (*bdy_ptr != 0)
                {
                    bspace[list_length++] = *bdy_ptr++;
                }
                Marshal.FreeHGlobal((IntPtr)(*bndy_list));

                if (list_length == 0) /* No boundary -> make everybody bndy. */
                {
                    for (i = 0; i < nvtxs; i++)
                    {
                        bspace[i] = i + 1;
                    }
                    list_length = nvtxs;
                }
                /* Set dvals to flag uninitialized vertices. */
                for (i = 1; i <= nvtxs; i++)
                {
                    dvals[i][0] = 3 * maxdval;
                }
            }
            else
            {
                list_length = nvtxs;
            }

            step_cutoff = KL_BAD_MOVES;
            cost_cutoff = maxdval * step_cutoff / 7;
            if (cost_cutoff < step_cutoff)
            {
                cost_cutoff = step_cutoff;
            }

            deltaminus = deltaplus = 0;
            for (i = 0; i < nsets; i++)
            {
                if (startweight[i] - goal[i] > deltaplus)
                {
                    deltaplus = startweight[i] - goal[i];
                }
                else if (goal[i] - startweight[i] > deltaminus)
                {
                    deltaminus = goal[i] - startweight[i];
                }
            }
            balanced = (deltaplus + deltaminus <= max_dev);

            bestg_min = -2.0 * nvtxs * maxdval;
            parity    = false;
            eweight   = (int)(cut_cost + .5);
            nbad      = 0;
            npass     = 0;
            improved  = 0;
            done      = false;
            while (!done)
            {
                npass++;
                ever_balanced = false;

                /* Initialize various quantities. */
                balance_best = 0;
                for (i = 0; i < nsets; i++)
                {
                    for (j = 0; j < nsets; j++)
                    {
                        tops[i][j] = 2 * maxdval;
                    }
                    weightsum[i]  = startweight[i];
                    loose[i]      = weightsum[i];
                    locked[i]     = 0;
                    balance_best += goal[i];
                }

                gtotal   = 0;
                bestg    = bestg_min;
                beststep = -1;

                movelist = null;
                endlist  = &movelist;

                neg_steps = 0;

                /* Compute the initial d-values, and bucket-sort them. */
                time = seconds();
                if (nsets == 2)
                {
                    bucketsorts_bi(graph, nvtxs, buckets, listspace, dvals, sets, term_wgts, maxdval, nsets,
                                   parity, hops, bspace, list_length, npass, useEdgeWeights);
                }
                else
                {
                    bucketsorts(graph, nvtxs, buckets, listspace, dvals, sets, term_wgts, maxdval, nsets, parity,
                                hops, bspace, list_length, npass, useEdgeWeights);
                }
                parity          = !parity;
                kl_bucket_time += seconds() - time;

                if (DEBUG_KL == DebugFlagKL.PrintBucket)
                {
                    pbuckets(buckets, listspace, maxdval, nsets);
                }

                /* Now determine the set of K-L moves. */

                for (step = 1;; step++)
                {
                    /* Find the highest d-value in each set. */
                    /* But only consider moves from large to small sets, or moves */
                    /* in which balance is preserved. */
                    /* Break ties in some nonarbitrary manner. */
                    bestval = -maxdval - 1;
                    for (i = 0; i < nsets; i++)
                    {
                        for (j = 0; j < nsets; j++)
                        {
                            /* Only allow moves from large sets to small sets, or */
                            /* moves which preserve balance. */
                            if (i != j)
                            {
                                /* Find the best move from i to j. */
                                for (k = tops[i][j]; k >= 0 && buckets[i][j][k] == null; k--)
                                {
                                    ;
                                }
                                tops[i][j] = k;

                                if (k >= 0)
                                {
                                    l       = (j > i) ? j - 1 : j;
                                    vtx     = ((int)(buckets[i][j][k] - listspace[l])) / size;
                                    vweight = graph[vtx]->vwgt;

                                    if ((enforce_balance_hard && weightsum[i] >= goal[i] && weightsum[j] <= goal[j] &&
                                         weightsum[i] - goal[i] - (weightsum[j] - goal[j]) > max_dev) ||
                                        (!enforce_balance_hard && weightsum[i] >= goal[i] && weightsum[j] <= goal[j]) ||
                                        (!enforce_balance_hard &&
                                         weightsum[i] - vweight - goal[i] > -(double)((max_dev + 1) / 2) &&
                                         weightsum[j] + vweight - goal[j] < (double)((max_dev + 1) / 2)))
                                    {
                                        /* Is it the best move seen so far? */
                                        if (k - maxdval > bestval)
                                        {
                                            bestval = k - maxdval;
                                            bestvtx = vtx;
                                            bestto  = j;
                                            /* DO I NEED ALL THIS DATA?  Just to break ties. */
                                            bestdelta = Math.Abs(weightsum[i] - vweight - goal[i]) +
                                                        Math.Abs(weightsum[j] + vweight - goal[j]);
                                            beststuck1 = (int)Math.Min(loose[i], goal[j] - locked[j]);
                                            beststuck2 = (int)Math.Max(loose[i], goal[j] - locked[j]);
                                        }

                                        else if (k - maxdval == bestval)
                                        {
                                            /* Tied.  Is better balanced than current best? */
                                            /* If tied, move among sets with most freedom. */
                                            stuck1st = (int)Math.Min(loose[i], goal[j] - locked[j]);
                                            stuck2nd = (int)Math.Max(loose[i], goal[j] - locked[j]);
                                            delta    = Math.Abs(weightsum[i] - vweight - goal[i]) +
                                                       Math.Abs(weightsum[j] + vweight - goal[j]);

                                            /* NOTE: Randomization in this check isn't ideal */
                                            /* if more than two guys are tied. */
                                            if (delta < bestdelta ||
                                                (delta == bestdelta &&
                                                 (stuck1st > beststuck1 ||
                                                  (stuck1st == beststuck1 &&
                                                   (stuck2nd > beststuck2 ||
                                                    (stuck2nd == beststuck2 && (KL_RANDOM && drandom() < .5)))))))
                                            {
                                                bestval    = k - maxdval;
                                                bestvtx    = vtx;
                                                bestto     = j;
                                                bestdelta  = delta;
                                                beststuck1 = stuck1st;
                                                beststuck2 = stuck2nd;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    if (bestval == -maxdval - 1) /* No allowed moves */
                    {
                        if (DEBUG_KL != DebugFlagKL.NoDebugging)
                        {
                            Console.WriteLine("No KL moves at step {0:d}.  bestg = {1:g} at step {2:d}.\n", step, bestg, beststep);
                        }
                        break;
                    }

                    bestptr  = &(listspace[0][bestvtx]);
                    bestfrom = sets[bestvtx];

                    vweight              = graph[bestvtx]->vwgt;
                    weightsum[bestto]   += vweight;
                    weightsum[bestfrom] -= vweight;
                    loose[bestfrom]     -= vweight;
                    locked[bestto]      += vweight;

                    if (enforce_balance) /* Check if this partition is balanced. */
                    {
                        deltaminus = deltaplus = 0;
                        for (i = 0; i < nsets; i++)
                        {
                            if (weightsum[i] - goal[i] > deltaplus)
                            {
                                deltaplus = weightsum[i] - goal[i];
                            }
                            else if (goal[i] - weightsum[i] > deltaminus)
                            {
                                deltaminus = goal[i] - weightsum[i];
                            }
                        }
                        balance_val   = deltaminus + deltaplus;
                        temp_balanced = (balance_val <= max_dev);
                        ever_balanced = (ever_balanced || temp_balanced);
                    }

                    gtotal += bestval;
                    if (((gtotal > bestg && (!enforce_balance || temp_balanced)) ||
                         (enforce_balance_hard && balance_val < balance_best)) &&
                        step != nvtxs)
                    {
                        bestg    = gtotal;
                        beststep = step;
                        if (enforce_balance_hard)
                        {
                            balance_best = balance_val;
                        }
                        if (temp_balanced)
                        {
                            enforce_balance_hard = false;
                        }
                    }

                    if (DEBUG_KL == DebugFlagKL.MoreInfo || DEBUG_KL == DebugFlagKL.PrintBucket)
                    {
                        Console.WriteLine("At KL step {0:d}, bestvtx={1:d}, bestval={2:d} ({3:d}-> {4:d})", step, bestvtx, bestval, bestfrom, bestto);
                    }

                    /* Monitor the stopping criteria. */
                    if (bestval < 0)
                    {
                        if (!enforce_balance || ever_balanced)
                        {
                            neg_steps++;
                        }
                        if (bestg != bestg_min)
                        {
                            neg_cost = (int)(bestg - gtotal);
                        }
                        else
                        {
                            neg_cost = -maxdval - 1;
                        }
                        if ((neg_steps > step_cutoff || neg_cost > cost_cutoff) &&
                            !(enforce_balance && bestg == bestg_min) && (beststep != step))
                        {
                            if (DEBUG_KL != DebugFlagKL.NoDebugging)
                            {
                                if (neg_steps > step_cutoff)
                                {
                                    Console.WriteLine("KL step cutoff at step {0:d}.  bestg = {1:g} at step {2:d}.", step, bestg, beststep);
                                }
                                else if (neg_cost > cost_cutoff)
                                {
                                    Console.WriteLine("KL cost cutoff at step {0:d}.  bestg = {1:g} at step {2:d}.", step, bestg, beststep);
                                }
                            }
                            break;
                        }
                    }
                    else if (bestval > 0)
                    {
                        neg_steps = 0;
                    }

                    /* Remove vertex from its buckets, and flag it as finished. */
                    l = 0;
                    for (k = 0; k < nsets; k++)
                    {
                        if (k != bestfrom)
                        {
                            dval = dvals[bestvtx][l] + maxdval;
                            removebilist(&listspace[l][bestvtx], &buckets[bestfrom][k][dval]);
                            l++;
                        }
                    }

                    /* Is there a better way to do this? */
                    sets[bestvtx] = -sets[bestvtx] - 1;

                    /* Set up the linked list of moved vertices. */
                    bestptr->next = null;
                    bestptr->prev = (bilist *)(ulong)bestto;
                    *endlist = bestptr;
                    endlist = &(bestptr->next);

                    /* Now update the d-values of all the neighbors */
                    edges = graph[bestvtx]->edges;
                    if (useEdgeWeights)
                    {
                        ewptr = graph[bestvtx]->ewgts;
                    }
                    for (j = graph[bestvtx]->nedges - 1; j != 0; j--)
                    {
                        neighbor = *(++edges);
                        if (useEdgeWeights)
                        {
                            eweight = (int)(*(++ewptr) * cut_cost + .5);
                        }

                        /* First make sure neighbor is alive. */
                        if (sets[neighbor] >= 0)
                        {
                            group = sets[neighbor];

                            if (dvals[neighbor][0] >= 3 * maxdval)
                            {
                                /* New vertex, not yet in buckets. */
                                /* Can't be neighbor of moved vtx, so compute */
                                /* initial dvals and buckets, then update. */
                                bucketsort1(graph, neighbor, buckets, listspace, dvals, sets, term_wgts, maxdval, nsets,
                                            hops, useEdgeWeights);
                            }

                            l = 0;
                            for (k = 0; k < nsets; k++)
                            {
                                if (k != group)
                                {
                                    diff = eweight * (hops[k][bestfrom] - hops[group][bestfrom] + hops[group][bestto] -
                                                      hops[k][bestto]);
                                    dval = dvals[neighbor][l] + maxdval;
                                    movebilist(&listspace[l][neighbor], &buckets[group][k][dval],
                                               &buckets[group][k][dval + diff]);
                                    dvals[neighbor][l] += diff;
                                    dval += diff;
                                    if (dval > tops[group][k])
                                    {
                                        tops[group][k] = dval;
                                    }
                                    l++;
                                }
                            }
                        }
                    }
                    if (DEBUG_KL == DebugFlagKL.PrintBucket)
                    {
                        pbuckets(buckets, listspace, maxdval, nsets);
                    }
                }

                /* Done with a pass; should we actually perform any swaps? */
                bptr = movelist;
                if (bestg > 0 || (bestg != bestg_min && !balanced && enforce_balance) ||
                    (bestg != bestg_min && balance_trouble))
                {
                    improved += (int)bestg;
                    for (i = 1; i <= beststep; i++)
                    {
                        vtx    = ((int)(bptr - listspace[0])) / size;
                        bestto = (int)(ulong)bptr->prev;
                        startweight[bestto]         += graph[vtx]->vwgt;
                        startweight[-sets[vtx] - 1] -= graph[vtx]->vwgt;
                        sets[vtx] = bestto;
                        bptr      = bptr->next;
                    }

                    deltaminus = deltaplus = 0;
                    for (i = 0; i < nsets; i++)
                    {
                        if (startweight[i] - goal[i] > deltaplus)
                        {
                            deltaplus = startweight[i] - goal[i];
                        }
                        else if (goal[i] - startweight[i] > deltaminus)
                        {
                            deltaminus = goal[i] - startweight[i];
                        }
                    }

                    /*
                     * printf(" deltaplus = %f, deltaminus = %f, max_dev = %d\n", deltaplus, deltaminus, max_dev);
                     */
                    balanced = (deltaplus + deltaminus <= max_dev);
                }
                else
                {
                    nbad++;
                }

                if (!balanced || bptr == movelist)
                {
                    if (enforce_balance)
                    {
                        if (enforce_balance_hard)
                        {
                            balance_trouble = true;
                        }
                        enforce_balance_hard = true;
                    }
                    enforce_balance = true;
                    nbad++;
                }

                worth_undoing = (step < undo_frac * nvtxs);
                done          = (nbad >= nbadtries && balanced);
                if (KL_MAX_PASS > 0)
                {
                    done = done || (npass == KL_MAX_PASS && balanced);
                }
                if (!done) /* Prepare for next pass. */
                {
                    if (KL_UNDO_LIST && worth_undoing && !balance_trouble)
                    {
                        /* Make a list of modified vertices for next bucketsort. */
                        /* Also, ensure these vertices are removed from their buckets. */
                        list_length =
                            make_kl_list(graph, movelist, buckets, listspace, sets, nsets, bspace, dvals, maxdval);
                    }
                }
                if (done || !(KL_UNDO_LIST && worth_undoing && !balance_trouble))
                {
                    /* Restore set numbers of remaining, altered vertices. */
                    while (bptr != null)
                    {
                        vtx       = ((int)(bptr - listspace[0])) / size;
                        sets[vtx] = -sets[vtx] - 1;
                        bptr      = bptr->next;
                    }
                    list_length = nvtxs;
                }

                if (done && *bndy_list != null)
                {
                    make_bndy_list(graph, movelist, buckets, listspace, sets, nsets, bspace, tops, bndy_list);
                }
            }

            if (DEBUG_KL != DebugFlagKL.NoDebugging)
            {
                Console.WriteLine("   KL required {0:d} passes to improve by {1:d}.", npass, improved);
            }

            Marshal.FreeHGlobal((IntPtr)loose);
            Marshal.FreeHGlobal((IntPtr)locked);
            Marshal.FreeHGlobal((IntPtr)weightsum);
            Marshal.FreeHGlobal((IntPtr)bspace);
            return(false);
        }