Exemple #1
0
        private static void inertial1d(vtx_data **graph,  /* graph data structure */
                                       int nvtxs,         /* number of vtxs in graph */
                                       bool cube_or_mesh, /* 0 => hypercube, d => d-dimensional mesh */
                                       int nsets,         /* number of sets to divide into */
                                       float *x,          /* x coordinates of vertices */
                                       int *sets,         /* set each vertex gets assigned to */
                                       double[] goal,     /* desired set sizes */
                                       bool using_vwgts   /* are vertex weights being used? */
                                       )
        {
            double *value; /* values passed to median routine */
            double  time;  /* timing variables */
            int *   space; /* space required by median routine */
            int     i;     /* loop counter */

            value = (double *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(double));

            /* Copy values into double precision array. */
            for (i = 1; i <= nvtxs; i++)
            {
                value[i] = x[i];
            }

/* Now find the median value and partition based upon it. */
            space = (int *)Marshal.AllocHGlobal(nvtxs * sizeof(int));

            time = seconds();
            rec_median_1(graph, value, nvtxs, space, cube_or_mesh, nsets, goal, using_vwgts, sets, true);
            median_time += seconds() - time;

            Marshal.FreeHGlobal((IntPtr)space);
            Marshal.FreeHGlobal((IntPtr)value);
        }
Exemple #2
0
        private static bool SameStructure(int node1, int node2, /* two vertices which might have same nonzeros */
                                          vtx_data **graph,     /* data structure for storing graph */
                                          int *scatter          /* array for checking vertex labelling */
                                          )
        {
            bool same; /* are two vertices indistinguisable? */
            int  i;    /* loop counter */

            scatter[node1] = node1;
            for (i = 1; i < graph[node1]->nedges; i++)
            {
                scatter[graph[node1]->edges[i]] = node1;
            }

            for (i = 1; i < graph[node2]->nedges; i++)
            {
                if (scatter[graph[node2]->edges[i]] != node1)
                {
                    break;
                }
            }
            same = (i == graph[node2]->nedges && scatter[node2] == node1);

            return(same);
        }
Exemple #3
0
        /* Check an extended eigenpair of A by direct multiplication. Uses
         * the Ay = extval*y + Dg form of the problem for convenience. */

        public static double checkeig_ext(double *err, double *work, /* work vector of length n */
                                          vtx_data **A, double *y, int n, double extval, double *vwsqrt,
                                          double *gvec, double eigtol,
                                          bool warnings /* don't want to see warning messages in one of the
                                                         *        contexts this is called */
                                          )
        {
            double resid; /* the extended eigen residual */

            splarax(err, A, n, y, vwsqrt, work);
            scadd(err, 1, n, -extval, y);
            cpvec(work, 1, n, gvec); /* only need if going to re-use gvec */
            scale_diag(work, 1, n, vwsqrt);
            scadd(err, 1, n, -1.0, work);
            resid = ch_norm(err, 1, n);

            if (DEBUG_EVECS > 0)
            {
                {
                    Trace.WriteLine($"  extended residual: {resid:g}");
                }
            }

            if (warnings && WARNING_EVECS > 0 && resid > eigtol)
            {
                Trace.WriteLine($"WARNING: Extended residual ({resid:g}) greater than tolerance ({eigtol:g}).");
            }

            return(resid);
        }
Exemple #4
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);
        }
Exemple #5
0
        public static void count_weights(vtx_data **graph,           /* data structure for graph */
                                         int nvtxs,                  /* number of vtxs in graph */
                                         int *sets,                  /* set each vertex is assigned to */
                                         int nsets,                  /* number of sets in this division */
                                         double []          weights, /* vertex weights in each set */
                                         bool using_vwgts            /* are vertex weights being used? */
                                         )

        {
            int i; /* loop counters */

            /* Compute the sum of vertex weights for each set. */
            for (i = 0; i < nsets; i++)
            {
                weights[i] = 0;
            }

            if (using_vwgts)
            {
                for (i = 1; i <= nvtxs; i++)
                {
                    weights[sets[i]] += graph[i]->vwgt;
                }
            }

            else
            {
                for (i = 1; i <= nvtxs; i++)
                {
                    weights[sets[i]]++;
                }
            }
        }
Exemple #6
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);
        }
Exemple #7
0
/* Set up data structures for refine_part. */
        private static void make_maps_ref(vtx_data **graph,                /* graph data structure */
                                          bilist *set_list,                /* lists of vertices in each set */
                                          bilist *vtx_elems,               /* start of storage for vertices */
                                          int *assignment,                 /* set assignments for graph */
                                          int *sub_assign,                 /* assignment file for subgraph */
                                          int set1, int set2,              /* set value denoting subgraph */
                                          int *glob2loc,                   /* graph -> subgraph numbering map */
                                          int *loc2glob,                   /* subgraph -> graph numbering map */
                                          int *psub_nvtxs,                 /* number of vtxs in subgraph */
                                          int *pvwgt_max,                  /* returned largest vwgt */
                                          int *pvwgt_sum1, int *pvwgt_sum2 /* returned set sizes */
                                          )
        {
            bilist *ptr;                  /* loops through set lists */
            int     vwgt_max;             /* largest vertex weight in subgraph */
            int     vwgt_sum1, vwgt_sum2; /* sum of vertex weights in sets */
            int     vtx;                  /* vertex in subgraph */
            int     size;                 /* array spacing */
            int     j;                    /* loop counter */

            size     = (int)(&(vtx_elems[1]) - &(vtx_elems[0]));
            j        = 1;
            vwgt_max = vwgt_sum1 = vwgt_sum2 = 0;
            for (ptr = set_list[set1].next; ptr != null; ptr = ptr->next)
            {
                vtx           = ((int)(ptr - vtx_elems)) / size;
                sub_assign[j] = 0;
                glob2loc[vtx] = j;
                loc2glob[j]   = vtx;
                if (graph[vtx]->vwgt > vwgt_max)
                {
                    vwgt_max = graph[vtx]->vwgt;
                }

                vwgt_sum1 += graph[vtx]->vwgt;
                j++;
            }

            for (ptr = set_list[set2].next; ptr != null; ptr = ptr->next)
            {
                vtx           = ((int)(ptr - vtx_elems)) / size;
                sub_assign[j] = 1;
                glob2loc[vtx] = j;
                loc2glob[j]   = vtx;
                if (graph[vtx]->vwgt > vwgt_max)
                {
                    vwgt_max = graph[vtx]->vwgt;
                }

                vwgt_sum2      += graph[vtx]->vwgt;
                assignment[vtx] = set1;
                j++;
            }

            *pvwgt_sum1 = vwgt_sum1;
            *pvwgt_sum2 = vwgt_sum2;
            *pvwgt_max  = vwgt_max;
            *psub_nvtxs = j - 1;
        }
Exemple #8
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="graph">data structure with vtx weights</param>
        /// <param name="yvecs">ptr to list of y-vectors (lengths nvtxs+1)</param>
        /// <param name="nvtxs">number of vertices in graph</param>
        /// <param name="ndims">number of vectors for dividing</param>
        /// <param name="cubeOrMesh">0 => hypercube, d => d-dimensional mesh</param>
        /// <param name="nsets">number of sets to divide into</param>
        /// <param name="wsqrt">sqrt of vertex weights</param>
        /// <param name="sets">processor assignment for my vtxs</param>
        /// <param name="active">space for nvtxs integers</param>
        /// <param name="mediantype">which partitioning strategy to use</param>
        /// <param name="goal">desired set sizes</param>
        /// <param name="vertexWeightMax">largest vertex weight</param>
        public static void Assign(vtx_data **graph, double *[] yvecs, int nvtxs, int ndims, bool cubeOrMesh, int nsets, double *wsqrt, int *sets, int *active, MappingType mediantype, double[] goal, int vertexWeightMax)
        {
            if (yvecs == null)
            {
                throw new ArgumentNullException(nameof(yvecs));
            }

            if (DEBUG_TRACE)
            {
                Trace.WriteLine($"<Entering {nameof(Assign)}, {nameof(nvtxs)} = {nvtxs:D}, {nameof(ndims)} = {ndims:D}>");
            }

            var useVertexWeights = vertexWeightMax != 1;

            switch (ndims)
            {
            case 1:
            {
                break;
            }

            case 2:
            {
                var theta = opt2d(graph, yvecs, nvtxs, nvtxs);
                Rotate2d(yvecs, nvtxs, theta);
                break;
            }

            case 3:
            {
                if (DEBUG_ASSIGN)
                {
                    var temp = tri_prod(yvecs[1], yvecs[2], yvecs[3], wsqrt, nvtxs);
                    Trace.WriteLine($"Before rotation, 3-way orthogonality = {temp:e}");
                }

                double phi, gamma, theta;     /* angles for optimal rotation */
                opt3d(graph, yvecs, nvtxs, nvtxs, wsqrt, &theta, &phi, &gamma, useVertexWeights);
                Rotate3d(yvecs, nvtxs, theta, phi, gamma);

                if (DEBUG_ASSIGN)
                {
                    var temp = tri_prod(yvecs[1], yvecs[2], yvecs[3], wsqrt, nvtxs);
                    Trace.WriteLine($"After rotation ({theta:f},{phi:f},{gamma:f}), 3-way orthogonality = {temp:e}");
                }

                break;
            }

            default:
            {
                throw new ArgumentOutOfRangeException(nameof(ndims));
            }
            }

            /* Unscale yvecs to get xvecs. */
            y2x(yvecs, ndims, nvtxs, wsqrt);
            mapper(graph, yvecs, nvtxs, active, sets, ndims, cubeOrMesh, nsets, mediantype, goal, vertexWeightMax);
        }
Exemple #9
0
        public static void map2d(vtx_data **graph,   /* data structure with vertex weights */
                                 double *[] xvecs,   /* vectors to partition */
                                 int vertexCount,    /* number of vertices */
                                 int *sets,          /* set each vertex gets assigned to */
                                 double[] goal,      /* desired set sizes */
                                 int maxVertexWeight /* largest vertex weight */
                                 )
        {
            double *[][] vals = new double *[4][]; /* values in sorted lists */
            for (var i = 0; i < vals.Length; i++)
            {
                vals[i] = new double *[MAXSETS];
            }

            double[]  dist    = new double[4];  /* trial separation point */
            double[]  size    = new double[4];  /* sizes of each set being modified */
            int *[][] indices = new int *[4][]; /* indices sorting lists */
            for (var i = 0; i < indices.Length; i++)
            {
                indices[i] = new int *[MAXSETS];
            }

            int[][] startvtx = new int[4][]; /* indices defining separation */
            for (var i = 0; i < startvtx.Length; i++)
            {
                startvtx[i] = new int[MAXSETS];
            }

            N_VTX_CHECKS = N_VTX_MOVES = 0;

            /* Generate all the lists of values that need to be sorted. */
            genvals2d(xvecs, vals, vertexCount);

            /* Sort the lists of values. */
            sorts2d(vals, indices, vertexCount);

            /* Now initialize dists and assign to sets. */
            inits2d(graph, xvecs, vals, indices, vertexCount, dist, startvtx, size, sets);

            /* Determine the largest and smallest allowed set sizes. */
            /* (For now, assume all sets must be same size, but can easily change.) */

            if (DEBUG_BPMATCH == DebugFlagBP.ErrorChecking)
            {
                Trace.WriteLine(" Calling check before movevtxs");
                checkbp(graph, xvecs, sets, dist, vertexCount, nsection);
            }

            movevtxs(graph, vertexCount, nsets, dist, indices, vals, startvtx, sets, size, goal, maxVertexWeight);

            if (DEBUG_BPMATCH != DebugFlagBP.NoDebugging)
            {
                Trace.WriteLine($" {nameof(N_VTX_CHECKS)} = {N_VTX_CHECKS:d}, {nameof(N_VTX_MOVES)} = {N_VTX_MOVES:d}");
                checkbp(graph, xvecs, sets, dist, vertexCount, nsection);
            }

            free2d(vals, indices);
        }
Exemple #10
0
        static float *old_ewgts;                              /* space for old edge weights */

        public static void compress_ewgts(vtx_data **graph,   /* list of graph info for each vertex */
                                          int nvtxs,          /* number of vertices in graph */
                                          int nedges,         /* number of edges in graph */
                                          double ewgt_max,    /* largest edge weight */
                                          bool useEdgeWeights /* are edge weights being used? */
                                          )
        {
            float *old_ewptr;   /* loops through old edge weights */
            float *new_ewptr;   /* loops through old edge weights */
            float *self_ptr;    /* points to self edge in new_ewgts */
            float *new_ewgts;   /* space for new edge weights */
            int    ewgt;        /* new edge weight value */
            double sum;         /* sum of all the new edge weights */
            double ratio;       /* amount to reduce edge weights */
            int    i, j;        /* loop counter */

            /* Check easy cases first. */
            if (!useEdgeWeights)
            {
                old_ewgts = null;
            }
            else if (ewgt_max < EWGT_RATIO_MAX * nvtxs)
            {
                /* If not too heavy, leave it alone. */
                old_ewgts = null;
                Trace.WriteLine($"In compress_ewgts, but not too heavy, ewgt_max = {ewgt_max:g}, nvtxs = {nvtxs:d}");
            }

            else /* Otherwise, compress edge weights. */
            /* Allocate space for new edge weights */
            {
                old_ewgts = graph[1]->ewgts;
                new_ewgts = (float *)Marshal.AllocHGlobal((2 * nedges + nvtxs) * sizeof(float));
                ratio     = (EWGT_RATIO_MAX * nvtxs) / ewgt_max;
                Trace.WriteLine("In compress_ewgts, ewgt_max = {ewgt_max:g}, nvtxs = {nvtxs:d}, ratio = {ratio:e}");
                old_ewptr = old_ewgts;
                new_ewptr = new_ewgts;
                for (i = 1; i <= nvtxs; i++)
                {
                    self_ptr = new_ewptr++;
                    old_ewptr++;
                    sum = 0;
                    for (j = graph[i]->nedges - 1; j != 0; j--)
                    {
                        ewgt           = (int)(*(old_ewptr++) * ratio + 1.0);
                        *(new_ewptr++) = (float)ewgt;
                        sum           += (float)ewgt;
                    }
                    *self_ptr = (float)-sum;
                    graph[i]->ewgts = self_ptr;
                }
            }
        }
Exemple #11
0
        /// <summary>
        /// Find a maximal matching in a graph using one of several algorithms.
        /// </summary>
        public static int maxmatch(vtx_data **graph,    /* array of vtx data for graph */
                                   int nvtxs,           /* number of vertices in graph */
                                   int nedges,          /* number of edges in graph */
                                   int *mflag,          /* flag indicating vtx selected or not */
                                   bool useEdgeWeights, /* are edge weights being used? */
                                   int igeom,           /* geometric dimensionality */
                                   float **coords       /* coordinates for each vertex */
                                   )
        {
            int nmerged = 0; /* number of matching edges found */

            if (MATCH_TYPE == MatchingRoutine.maxmatch1 || (MATCH_TYPE == MatchingRoutine.maxmatch5_geometric && coords == null))
            {
                /* Dumb, fast routine. */
                nmerged = maxmatch1(graph, nvtxs, mflag, useEdgeWeights);
            }

            else if (MATCH_TYPE == MatchingRoutine.maxmatch2)
            {
                /* More random but somewhat slower. */
                nmerged = maxmatch2(graph, nvtxs, mflag, useEdgeWeights);
            }

            else if (MATCH_TYPE == MatchingRoutine.maxmatch3)
            {
                /* Much more random but slower still. */
                nmerged = maxmatch3(graph, nvtxs, mflag, useEdgeWeights);
            }

            else if (MATCH_TYPE == MatchingRoutine.maxmatch4_Luby)
            {
                /* Truly random but very slow. */
                nmerged = maxmatch4(graph, nvtxs, nedges, mflag, useEdgeWeights);
            }
            else if (MATCH_TYPE == MatchingRoutine.maxmatch5_geometric && coords != null)
            {
                /* Geometric nearness. */
                nmerged = maxmatch5(graph, nvtxs, mflag, igeom, coords);
            }

            else if (MATCH_TYPE == MatchingRoutine.maxmatch9_minimumVertexDegree)
            {
                /* Minimum degree of merged vertex */
                nmerged = maxmatch9(graph, nvtxs, mflag, useEdgeWeights);
            }

            if (DEBUG_COARSEN)
            {
                Trace.WriteLine($"Number of matching edges = {nmerged:D}");
            }

            return(nmerged);
        }
Exemple #12
0
        public static void coarsen1(vtx_data **graph,    /* array of vtx data for graph */
                                    int nvtxs,           /* number of vertices in graph */
                                    int nedges,          /* number of edges in graph */
                                    vtx_data ***pcgraph, /* coarsened version of graph */
                                    int *pcnvtxs,        /* number of vtxs in coarsened graph */
                                    int *pcnedges,       /* number of edges in coarsened graph */
                                    int **pv2cv,         /* pointer to v2cv */
                                    int igeom,           /* dimension for geometric information */
                                    float **coords,      /* coordinates for vertices */
                                    float **ccoords,     /* coordinates for coarsened vertices */
                                    bool useEdgeWeights  /* are edge weights being used? */
                                    )
        {
            double time;    /* time routine is entered */
            int *  v2cv;    /* maps from vtxs to cvtxs */
            int *  mflag;   /* flag indicating vtx matched or not */
            int    cnvtxs;  /* number of vtxs in coarse graph */
            int    nmerged; /* number of edges contracted */

            time = seconds();

            /* Allocate and initialize space. */
            v2cv  = (int *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(int));
            mflag = (int *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(int));

            /* Find a maximal matching in the graph. */
            nmerged     = maxmatch(graph, nvtxs, nedges, mflag, useEdgeWeights, igeom, coords);
            match_time += seconds() - time;

            /* Now construct coarser graph by contracting along matching edges. */
            /* Pairs of values in mflag array indicate matched vertices. */
            /* A zero value indicates that vertex is unmatched. */

            /*
             *  makecgraph(graph, nvtxs, pcgraph, pcnvtxs, pcnedges, mflag, *pv2cv, nmerged, useEdgeWeights, igeom, coords, ccoords);
             *  makecgraph2(graph, nvtxs, nedges, pcgraph, pcnvtxs, pcnedges, mflag, *pv2cv, nmerged, useEdgeWeights, igeom, coords, ccoords);
             */

            makev2cv(mflag, nvtxs, v2cv);

            Marshal.FreeHGlobal((IntPtr)mflag);

            cnvtxs = nvtxs - nmerged;
            makefgraph(graph, nvtxs, nedges, pcgraph, cnvtxs, pcnedges, v2cv, useEdgeWeights, igeom, coords,
                       ccoords);

            *pcnvtxs = cnvtxs;
            *pv2cv   = v2cv;
            coarsen_time += seconds() - time;
        }
Exemple #13
0
 public static void median_assign(vtx_data **graph, /* data structure with vertex weights */
                                  double *vals,     /* values of which to find median */
                                  int nvtxs,        /* number of values I own */
                                  double[] goal,    /* desired sizes for sets */
                                  bool using_vwgts, /* are vertex weights being used? */
                                  int *sets,        /* assigned set for each vertex */
                                  double wlow,      /* sum of weights below guess */
                                  double whigh,     /* sum of weights above guess */
                                  double guess      /* median value */
                                  )
 {
     for (var i = 1; i <= nvtxs; i++)
     {
         if (vals[i] < guess)
         {
             sets[i] = 0;
         }
         else if (vals[i] > guess)
         {
             sets[i] = 1;
         }
         else
         {
             if (goal[0] - wlow > goal[1] - whigh)
             {
                 sets[i] = 0;
                 if (using_vwgts)
                 {
                     wlow += graph[i]->vwgt;
                 }
                 else
                 {
                     wlow++;
                 }
             }
             else
             {
                 sets[i] = 1;
                 if (using_vwgts)
                 {
                     whigh += graph[i]->vwgt;
                 }
                 else
                 {
                     whigh++;
                 }
             }
         }
     }
 }
Exemple #14
0
        public static void print_sep_size(int *list, vtx_data **graph /* array of vtx data for graph */
                                          )
        {
            int sep_size, sep_weight;
            int i;

            sep_size = sep_weight = 0;
            for (i = 0; list[i] != 0; i++)
            {
                sep_size++;
                sep_weight += graph[list[i]]->vwgt;
            }
            Trace.WriteLine($" {nameof(sep_size)} = {sep_size:d}, {nameof(sep_weight)} = {sep_weight:d}");
        }
Exemple #15
0
        /// <summary>
        /// BFS to find connected component.
        /// </summary>
        /// <param name="graph">graph data structure</param>
        /// <param name="root">start vertex for DFS</param>
        /// <param name="count">number of vertices in component</param>
        /// <param name="mark">has vtx been seen?</param>
        /// <param name="vtxlist">space for storing vtxs to search</param>
        /// <param name="currentComponentNumber">current component number</param>
        /// <returns></returns>
        public static int bfsearch(vtx_data **graph, int root, int *count, int *mark, int *vtxlist, int currentComponentNumber)
        {
            var firstVertex = 1;

            var lastVertexInList = 1;

            mark[root] = currentComponentNumber;
            vtxlist[0] = root;

            // Copy root's neighbors to vtxlist, incrementing count
            var edgePointer = graph[root]->edges;

            if (graph[root]->nedges - 1 < 0)
            {
                throw new InvalidOperationException("A node should have at least one edge");
            }
            for (var i = graph[root]->nedges - 1; i != 0; i--)
            {
                // neighbor of vertex
                var neighbor = *(++edgePointer);
                vtxlist[lastVertexInList++] = neighbor;
                mark[neighbor] = currentComponentNumber;
            }

            while (firstVertex < lastVertexInList)
            {
                // vertex being processed
                var vtx = vtxlist[firstVertex++];
                // Loop through neighbors, copying to vtxlist if unmarked.
                var iptr = graph[vtx]->edges;
                if (graph[vtx]->nedges - 1 < 0)
                {
                    throw new InvalidOperationException("A node should have at least one edge");
                }
                for (var i = graph[vtx]->nedges - 1; i != 0; i--)
                {
                    // neighbor of vertex
                    var neighbor = *(++iptr);
                    if (mark[neighbor] != currentComponentNumber)
                    {
                        mark[neighbor] = currentComponentNumber;
                        vtxlist[lastVertexInList++] = neighbor;
                    }
                }
            }

            *count += lastVertexInList;
            return(vtxlist[lastVertexInList - 1]);
        }
Exemple #16
0
        public static void countup_vtx_sep(vtx_data **graph, /* list of graph info for each vertex */
                                           int nvtxs,        /* number of vertices in graph */
                                           int *sets         /* local partitioning of vtxs */
                                           )
        {
            int vtx, set; /* vertex and set in graph */
            int sep_size; /* size of the separator */
            int i, j, k;  /* loop counters */

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

                if (sets[i] == 1)
                {
                    k += graph[i]->vwgt;
                }

                if (sets[i] == 2)
                {
                    sep_size += graph[i]->vwgt;
                }
            }

            Trace.WriteLine($"Set sizes = {j:d}/{k:d}, Separator size = {sep_size:d}\n");

            /* Now check that it really is a separator. */
            for (i = 1; i <= nvtxs; i++)
            {
                set = sets[i];
                if (set != 2)
                {
                    for (j = 1; j < graph[i]->nedges; j++)
                    {
                        vtx = graph[i]->edges[j];
                        if (sets[vtx] != 2 && sets[vtx] != set)
                        {
                            Trace.WriteLine($"Error: {i:d} (set {set:d}) adjacent to {vtx:d} (set {sets[vtx]:d})");
                        }
                    }
                }
            }
        }
Exemple #17
0
        public static void make_connected(
            /* Add edges to make graph connected. */
            vtx_data **graph,     /* graph data structure */
            int nvtxs,            /* number of vertices in graph */
            int *nedges,          /* number of edges in graph */
            int *mark,            /* space for nvtxs+1 ints */
            int *vtxlist,         /* space for nvtxs ints */
            connect_data **cdata, /* space for connectivity data */
            bool useEdgeWeights   /* are edges of graph weighted? */
            )
        {
            edgeslist *new_edges; /* list of edges connecting graph */
            edgeslist *prev_edge; /* pointer for manipulating edge list */
            edgeslist *curr_edge; /* pointer for manipulating edge list */
            edgeslist *next_edge; /* pointer for manipulating edge list */
            int        nadded;    /* number of edges being added */

            /* First find edges needed to make graph connected. */
            nadded = find_edges(graph, nvtxs, mark, vtxlist, &new_edges);

            /* Now add these needed edges to graph data structure if needed. */
            if (nadded == 0)
            {
                *cdata = null;
            }
            else
            {
                *cdata = (connect_data *)Marshal.AllocHGlobal(sizeof(connect_data));
                (*cdata)->old_edges = null;
                (*cdata)->old_ewgts = null;
                add_edges(graph, new_edges, &(*cdata)->old_edges, &(*cdata)->old_ewgts, useEdgeWeights);
                *nedges += nadded;

                /* Now, reverse the order of the new_edges list for consistency with */
                /* the removal order. */
                curr_edge       = new_edges->next;
                new_edges->next = null;
                prev_edge       = new_edges;
                while (curr_edge != null)
                {
                    next_edge       = curr_edge->next;
                    curr_edge->next = prev_edge;
                    prev_edge       = curr_edge;
                    curr_edge       = next_edge;
                }
                (*cdata)->new_edges = prev_edge;
            }
        }
Exemple #18
0
        /// <summary>
        /// Breadth first search algorithm to find & mark connected components.
        /// Returns list of edges to connect them together.
        /// </summary>
        /// <param name="graph">graph data structure</param>
        /// <param name="nvtxs">number of vertices in graph</param>
        /// <param name="mark">space for nvtxs+1 ints</param>
        /// <param name="vtxlist">space for nvtxs ints</param>
        /// <param name="edges">list of edges connecting graph</param>
        /// <returns></returns>
        public static int find_edges(vtx_data **graph, int nvtxs, int *mark, int *vtxlist, edgeslist **edges)
        {
            Trace.WriteLine($"<Entering {nameof(find_edges)}>");
            for (var i = 1; i <= nvtxs; i++)
            {
                mark[i] = -1;
            }

            var visitedVertexCount = 0;
            var edgesAdded         = 0;

            *edges = null;
            // vertex to start the dfs
            var root = (int)(nvtxs * drandom()) + 1;

            // last vertex seen in BFS
            var last = bfsearch(graph, root, &visitedVertexCount, mark, vtxlist, edgesAdded);

            while (visitedVertexCount != nvtxs)
            {
                // Are there any remaining vertices?
                // Find starting vtx for next BFS.
                root = (int)(nvtxs * drandom()) + 1;
                //Trace.WriteLine($"looking for next root from: {root}");
                while (mark[root] >= 0)
                {
                    root++;
                    if (root > nvtxs)
                    {
                        root = 1;
                    }
                }



                // Add new edge to list needed for connectivity.
                var newedge = (edgeslist *)Marshal.AllocHGlobal(sizeof(edgeslist));
                newedge->next = *edges;
                newedge->vtx1 = last;
                newedge->vtx2 = root;
                *edges = newedge;
                edgesAdded++;
                last = bfsearch(graph, root, &visitedVertexCount, mark, vtxlist, edgesAdded);
            }

            return(edgesAdded);
        }
Exemple #19
0
        /* Find vertices on boundary of partition, and change their assignments. */

        public static int find_bndy(vtx_data **graph, /* array of vtx data for graph */
                                    int nvtxs,        /* number of vertices in graph */
                                    int *assignment,  /* processor each vertex gets assigned to */
                                    int new_val,      /* assignment value for boundary vtxs */
                                    int **pbndy_list  /* returned list, end with zero */
                                    )
        {
            int *bndy_list;   /* returned list, end with zero */
            int *edges;       /* loops through edge list */
            int  list_length; /* returned number of vtxs on boundary */
            int  set, set2;   /* set a vertex is in */
            int  i, j;        /* loop counters */

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

            list_length = 0;
            for (i = 1; i <= nvtxs; i++)
            {
                set   = assignment[i];
                edges = graph[i]->edges;
                for (j = graph[i]->nedges - 1; j != 0; j--)
                {
                    set2 = assignment[*(++edges)];
                    if (set2 != set)
                    {
                        bndy_list[list_length++] = i;
                        break;
                    }
                }
            }

            bndy_list[list_length] = 0;

            for (i = 0; i < list_length; i++)
            {
                assignment[bndy_list[i]] = new_val;
            }

            /* Shrink out unnecessary space */
            *pbndy_list = (int *)Marshal.ReAllocHGlobal((IntPtr)bndy_list, new IntPtr((list_length + 1) * sizeof(int)));

            return(list_length);
        }
Exemple #20
0
        private static void clear_dvals(vtx_data **graph, /* data structure for graph */
                                        int nvtxs,        /* number of vtxs in graph */
                                        int *ldvals,      /* d-values for each transition */
                                        int *rdvals,      /* d-values for each transition */
                                        int *bspace,      /* list of activated vertices */
                                        int list_length   /* number of activated vertices */
                                        )
        {
            int *edges;    /* loops through edge list */
            int  vtx;      /* vertex in bspace */
            int  neighbor; /* neighbor of vtx */
            int  i, j;     /* loop counters */

            if (list_length > .05 * nvtxs)
            {
                /* Do it directly. */
                for (i = 1; i <= nvtxs; i++)
                {
                    ldvals[i] = rdvals[i] = 0;
                }
            }
            else
            {
                /* Do it more carefully */
                for (i = 0; i < list_length; i++)
                {
                    vtx = bspace[i];
                    if (vtx < 0)
                    {
                        vtx = -vtx;
                    }

                    ldvals[vtx] = rdvals[vtx] = 0;
                    edges       = graph[vtx]->edges;
                    for (j = graph[vtx]->nedges - 1; j != 0; j--)
                    {
                        neighbor         = *(++edges);
                        ldvals[neighbor] = rdvals[neighbor] = 0;
                    }
                }
            }
        }
Exemple #21
0
        /// <summary>
        /// Breadth first search algorithm to find & mark connected components.
        /// </summary>
        /// <param name="graph">graph data structure</param>
        /// <param name="nvtxs">number of vertices in graph</param>
        /// <param name="mark">space for nvtxs+1 ints</param>
        /// <param name="vtxlist">space for nvtxs ints</param>
        /// <returns>The number of connected components.</returns>
        public static int find_comps(vtx_data **graph, int nvtxs, int *mark, int *vtxlist)
        {
            Trace.WriteLine($"<Entering {nameof(find_comps)}>");

            for (var i = 1; i <= nvtxs; i++)
            {
                mark[i] = -1;
            }

            var visitedVertexCount = 0;
            var componentCount     = 0;
            // vertex to start the dfs
            var root = (int)(nvtxs * drandom()) + 1;

            bfsearch(graph, root, &visitedVertexCount, mark, vtxlist, componentCount);

            // Are there any remaining vertices?
            while (visitedVertexCount != nvtxs)
            {
                // Find starting vtx for next BFS.
                root = (int)(nvtxs * drandom()) + 1;
                while (mark[root] >= 0)
                {
                    root++;
                    if (root > nvtxs)
                    {
                        root = 1;
                    }
                }

                // Add new edge to list needed for connectivity.
                componentCount++;
                bfsearch(graph, root, &visitedVertexCount, mark, vtxlist, componentCount);
                Trace.WriteLine($"Visited {visitedVertexCount} out of {nvtxs} vertices");
            }

            Trace.WriteLine($"<Exiting {nameof(find_comps)}>");

            return(componentCount + 1);
        }
Exemple #22
0
        public static void makevwsqrt(double *vwsqrt, vtx_data **graph, int nvtxs)
/* Make vector of square roots of vertex weights. */
/* vector returned */
/* graph data structure */
/* number of vertices in graph */
        {
            int vwgt; /* vertex weight */
            int i;    /* loop counter */

            for (i = 1; i <= nvtxs; i++)
            {
                vwgt = graph[i]->vwgt;
                if (vwgt <= NSQRTS)
                {
                    vwsqrt[i] = SQRTS[vwgt];
                }
                else
                {
                    vwsqrt[i] = Math.Sqrt(vwgt);
                }
            }
        }
Exemple #23
0
        public static void restore_ewgts(vtx_data **graph, /* list of graph info for each vertex */
                                         int nvtxs         /* number of vertices in graph */
                                         )
        {
            int i; /* loop counter */

            /* Check easy case first. */
            if (old_ewgts == null)
            {
                return;
            }
            else /* otherwise, compress edge weights. */
            {
                Marshal.FreeHGlobal((IntPtr)(graph[1]->ewgts));
                for (i = 1; i <= nvtxs; i++)
                {
                    graph[i]->ewgts = old_ewgts;
                    old_ewgts      += graph[i]->nedges;
                }
                old_ewgts = null;
            }
        }
Exemple #24
0
        private static void compute_cube_vdata(refine_vdata *vdata,   /* preference data for a vertex */
                                               vtx_data **comm_graph, /* communication graph data structure */
                                               int vtx,               /* current vertex */
                                               int mask,              /* bit set in current hypercube dimension */
                                               int *vtx2node          /* maps graph vtxs to mesh nodes */
                                               )
        {
            float same;        /* my preference to stay where I am */
            float change;      /* my preference to change this bit */
            float ewgt;        /* weight of an edge */
            int   neighbor;    /* neighboring vtx in comm_graph */
            int   my_side;     /* which side of hypercube I'm on */
            int   neighb_side; /* which side of hypercube neighbor's on */
            int   j;           /* loop counter */

            my_side = (vtx2node[vtx] & mask);

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

                neighb_side = (vtx2node[neighbor] & mask);

                if (neighb_side != my_side)
                {
                    change += ewgt;
                }
                else
                {
                    same += ewgt;
                }
            }
            vdata->same  = same;
            vdata->above = change;
        }
Exemple #25
0
        /// <summary>
        /// Undo the construction of the subgraph.
        /// </summary>
        /// <param name="subgraph">subgraph data structure</param>
        /// <param name="subnvtxs">number of vtxs in subgraph</param>
        /// <param name="loc2glob">mapping from subgraph to graph numbering</param>
        /// <param name="degree">degrees of vertices in graph</param>
        /// <param name="useEdgeWeights">are edge weights being used?</param>
        public static void remake_graph(vtx_data **subgraph, int subnvtxs, int *loc2glob, int *degree, bool useEdgeWeights)
        {
            Trace.WriteLine($"<Entering {nameof(remake_graph)}>");

            vtx_data *subgptr; /* loops through subgraph */
            double    ewgtsum; /* sum of weights of subgraph edges */
            int       nedges;  /* vertex degree in subgraph */

            /* For each vertex in subgraph, expand the edge set back out. */
            for (var i = 1; i <= subnvtxs; i++)
            {
                subgptr           = subgraph[i];
                subgptr->edges[0] = loc2glob[i];
                nedges            = subgptr->nedges;
                /* Change edges back to global numbering system. */
                var iptr = subgptr->edges; /* loops through adjacency list */
                for (var j = nedges - 1; j != 0; j--)
                {
                    iptr++;
                    *iptr = loc2glob[*iptr];
                }

                subgptr->nedges = degree[i];

                /* Now get the diagonal value right. */
                if (useEdgeWeights)
                {
                    ewgtsum = 0;
                    var fptr = subgptr->ewgts; /* loops through edge weights */
                    for (var j = degree[i] - 1; j != 0; j--)
                    {
                        ewgtsum += *(++fptr);
                    }

                    subgptr->ewgts[0] = (float)-ewgtsum;
                }
            }
        }
Exemple #26
0
        public static bool flatten(vtx_data **graph,    /* array of vtx data for graph */
                                   int nvtxs,           /* number of vertices in graph */
                                   int nedges,          /* number of edges in graph */
                                   vtx_data ***pcgraph, /* coarsened version of graph */
                                   int *pcnvtxs,        /* number of vtxs in coarsened graph */
                                   int *pcnedges,       /* number of edges in coarsened graph */
                                   int **pv2cv,         /* pointer to v2cv */
                                   bool useEdgeWeights, /* are edge weights being used? */
                                   int igeom,           /* dimensions of geometric data */
                                   float **coords,      /* coordinates for vertices */
                                   float **ccoords      /* coordinates for coarsened vertices */
                                   )
        {
            double Thresh; /* minimal acceptable size reduction */
            int *  v2cv;   /* map from vtxs to coarse vtxs */
            int    cnvtxs; /* number of vertices in flattened graph */

            Thresh = .9;

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

            find_flat(graph, nvtxs, &cnvtxs, v2cv);

            if (cnvtxs <= Thresh * nvtxs) /* Sufficient shrinkage? */
            {
                makefgraph(graph, nvtxs, nedges, pcgraph, cnvtxs, pcnedges, v2cv, useEdgeWeights, igeom, coords,
                           ccoords);

                *pcnvtxs = cnvtxs;
                *pv2cv   = v2cv;
                return(true);
            }

            /* Not worth bothering */
            Marshal.FreeHGlobal((IntPtr)v2cv);
            return(false);
        }
Exemple #27
0
        /// <summary>
        /// Free a graph data structure.
        /// </summary>
        public static void free_graph(vtx_data **graph)
        {
            if (graph == null)
            {
                return;
            }

            if (graph[1] != null)
            {
                if (graph[1]->ewgts != null)
                {
                    Marshal.FreeHGlobal((IntPtr)graph[1]->ewgts);
                }

                if (graph[1]->edges != null)
                {
                    Marshal.FreeHGlobal((IntPtr)graph[1]->edges);
                }

                Marshal.FreeHGlobal((IntPtr)graph[1]);
            }

            Marshal.FreeHGlobal((IntPtr)graph);
        }
Exemple #28
0
        /// <summary>
        /// Benchmark certain kernel operations
        /// </summary>
        /// <param name="A">matrix/graph being analyzed</param>
        /// <param name="n">number of rows/columns in matrix</param>
        /// <param name="vwsqrt">square roots of vertex weights</param>
        public static void time_kernels(vtx_data **A, int n, double *vwsqrt)
        {
            const double minTime    = 0.5;
            const double targetTime = 1.0;

            int    i;
            float *vwsqrtFloat;
            double time;

            if (DEBUG_TRACE)
            {
                Trace.WriteLine("<Entering time_kernels>");
            }

            const int beg = 1;
            var       end = n;

            var dvec1 = mkvec(beg, end);
            var dvec2 = mkvec(beg, end);
            var dvec3 = mkvec(beg - 1, end);
            var svec1 = mkvec_float(beg, end);
            var svec2 = mkvec_float(beg, end);
            var svec3 = mkvec_float(beg - 1, end);

            if (vwsqrt == null)
            {
                vwsqrtFloat = null;
            }
            else
            {
                vwsqrtFloat = mkvec_float(beg - 1, end);
                for (i = beg - 1; i <= end; i++)
                {
                    vwsqrtFloat[i] = (float)vwsqrt[i];
                }
            }

            vecran(dvec1, beg, end);
            vecran(dvec2, beg, end);
            vecran(dvec3, beg, end);
            for (i = beg; i <= end; i++)
            {
                svec1[i] = (float)dvec1[i];
                svec2[i] = (float)dvec2[i];
                svec3[i] = (float)dvec3[i];
            }

            // Set number of loops so that ch_norm() takes about one second.
            // This should insulate against inaccurate timings on faster machines.

            var    normDvec = 0.0d;
            var    loops    = 1;
            double timeDvec = 0;

            while (timeDvec < minTime)
            {
                time = seconds();
                for (i = loops; i != 0; i--)
                {
                    normDvec = ch_norm(dvec1, beg, end);
                }

                timeDvec = seconds() - time;
                if (timeDvec < minTime)
                {
                    loops = 10 * loops;
                }
            }

            loops = (int)((targetTime / timeDvec) * loops);
            if (loops < 1)
            {
                loops = 1;
            }

            Trace.WriteLine("                Kernel benchmarking");
            Trace.WriteLine($"Time (in seconds) for {loops:d} loops of each operation:\n");

            Trace.WriteLine("Routine      Double     Float      Discrepancy      Description");
            Trace.WriteLine("-------      ------     -----      -----------      -----------");

            /* Norm operation */
            time = seconds();
            for (i = loops; i != 0; i--)
            {
                normDvec = ch_norm(dvec1, beg, end);
            }

            timeDvec = seconds() - time;

            time = seconds();
            var normSvec = 0.0d;

            for (i = loops; i != 0; i--)
            {
                normSvec = norm_float(svec1, beg, end);
            }

            var timeSvec = seconds() - time;

            var diff = normDvec - normSvec;

            Trace.Write($"norm        {timeDvec:f}    {timeSvec:f}    {diff:e}");
            Trace.WriteLine("      2 norm");

            /* Dot operation */
            time = seconds();
            var dotDvec = 0.0d;

            for (i = loops; i != 0; i--)
            {
                dotDvec = dot(dvec1, beg, end, dvec2);
            }

            timeDvec = seconds() - time;

            time = seconds();
            var dotSvec = 0.0d;

            for (i = loops; i != 0; i--)
            {
                dotSvec = dot_float(svec1, beg, end, svec2);
            }

            timeSvec = seconds() - time;

            diff = dotDvec - dotSvec;
            Trace.Write($"dot         {timeDvec:f}    {timeSvec:f}    {diff:e}");
            Trace.WriteLine("      scalar product");

            /* Scadd operation */
            const double factor      = 1.01d;
            const float  factorFloat = (float)factor;

            var fac = factor;

            time = seconds();
            for (i = loops; i != 0; i--)
            {
                scadd(dvec1, beg, end, fac, dvec2);
                fac = -fac; /* to keep things in scale */
            }

            timeDvec = seconds() - time;

            var facFloat = factorFloat;

            time = seconds();
            for (i = loops; i != 0; i--)
            {
                scadd_float(svec1, beg, end, facFloat, svec2);
                facFloat = -facFloat; /* to keep things in scale */
            }

            timeSvec = seconds() - time;

            diff = checkvec(dvec1, beg, end, svec1);
            Trace.Write($"scadd       {timeDvec:f}    {timeSvec:f}    {diff:e}");
            Trace.WriteLine("      vec1 <- vec1 + alpha*vec2");

            /* Update operation */
            time = seconds();
            for (i = loops; i != 0; i--)
            {
                update(dvec1, beg, end, dvec2, factor, dvec3);
            }

            timeDvec = seconds() - time;

            time = seconds();
            for (i = loops; i != 0; i--)
            {
                update_float(svec1, beg, end, svec2, factorFloat, svec3);
            }

            timeSvec = seconds() - time;

            diff = checkvec(dvec1, beg, end, svec1);
            Trace.Write($"update      {timeDvec:f}    {timeSvec:f}    {diff:g}");
            Trace.WriteLine("      vec1 <- vec2 + alpha*vec3");

            /* splarax operation */
            if (PERTURB)
            {
                if (NPERTURB > 0 && PERTURB_MAX > 0.0)
                {
                    perturb_init(n);
                    if (DEBUG_PERTURB)
                    {
                        Trace.WriteLine($"Matrix being perturbed with scale {PERTURB_MAX:e}");
                    }
                }
                else if (DEBUG_PERTURB)
                {
                    Trace.WriteLine("Matrix not being perturbed");
                }
            }

            time = seconds();
            for (i = loops; i != 0; i--)
            {
                splarax(dvec1, A, n, dvec2, vwsqrt, dvec3);
            }

            timeDvec = seconds() - time;

            time = seconds();
            for (i = loops; i != 0; i--)
            {
                splarax_float(svec1, A, n, svec2, vwsqrtFloat, svec3);
            }

            timeSvec = seconds() - time;

            diff = checkvec(dvec1, beg, end, svec1);
            Trace.Write($"splarax     {timeDvec:f}    {timeSvec:f}    {diff:e}");
            Trace.WriteLine("      sparse matrix vector multiply");

            if (PERTURB && NPERTURB > 0 && PERTURB_MAX > 0.0)
            {
                perturb_clear();
            }

            Trace.WriteLine("");

            /* Free memory */
            frvec(dvec1, 1);
            frvec(dvec2, 1);
            frvec(dvec3, 0);
            frvec_float(svec1, 1);
            frvec_float(svec2, 1);
            frvec_float(svec3, 0);
            if (vwsqrtFloat != null)
            {
                frvec_float(vwsqrtFloat, beg - 1);
            }
        }
Exemple #29
0
        /* See comments in lanczos_SO() */

        public static void lanczos_SO_float(vtx_data **A,           /* sparse matrix in row linked list format */
                                            int n,                  /* problem size */
                                            int d,                  /* problem dimension = number of eigvecs to find */
                                            double *[] y,           /* columns of y are eigenvectors of A  */
                                            double[] lambda,        /* ritz approximation to eigenvals of A */
                                            double[] bound,         /* on ritz pair approximations to eig pairs of A */
                                            double eigtol,          /* tolerance on eigenvectors */
                                            double *vwsqrt,         /* square roots of vertex weights */
                                            double maxdeg,          /* maximum degree of graph */
                                            int version,            /* flags which version of sel. orth. to use */
                                            bool cube_or_mesh,      /* 0 => hypercube, d => d-dimensional mesh */
                                            int nsets,              /* number of sets to divide into */
                                            int *assignment,        /* set number of each vtx (length n+1) */
                                            int *active,            /* space for nvtxs integers */
                                            MappingType mediantype, /* which partitioning strategy to use */
                                            double[] goal,          /* desired set sizes */
                                            int vwgt_max            /* largest vertex weight */
                                            )
        {
            double           bis_safety;            /* real safety factor for T bisection */
            int              i, j, k;               /* indices */
            int              maxj;                  /* maximum number of Lanczos iterations */
            float *          u;
            float *          r;                     /* Lanczos vectors */
            double *         u_double;              /* double version of u */
            double *         alpha;
            double *         beta;                  /* the Lanczos scalars from each step */
            double *         ritz;                  /* copy of alpha for ql */
            double *         workj;                 /* work vector, e.g. copy of beta for ql */
            float *          workn;                 /* work vector, e.g. product Av for checkeig */
            double *         workn_double;          /* work vector, e.g. product Av for checkeig */
            double *         s;                     /* eigenvector of T */
            float **         q;                     /* columns of q are Lanczos basis vectors */
            double *         bj;                    /* beta(j)*(last el. of corr. eigvec s of T) */
            double           Sres;                  /* how well Tevec calculated eigvec s */
            double           Sres_max;              /* Max value of Sres */
            bool             inc_bis_safety;        /* need to increase bisection safety */
            double *         Ares;                  /* how well Lanczos calc. eigpair lambda,y */
            int *            index;                 /* the Ritz index of an eigenpair */
            orthlink_float **solist;                /* vec. of structs with vecs. to orthog. against */
            scanlink *       scanlist;              /* linked list of fields to do with min ritz vals */
            scanlink *       curlnk;                /* for traversing the scanlist */
            double           bji_tol;               /* tol on bji est. of eigen residual of A */
            bool             converged;             /* has the iteration converged? */
            double           goodtol;               /* error tolerance for a good Ritz vector */
            int              ngood;                 /* total number of good Ritz pairs at current step */
            int              maxngood;              /* biggest val of ngood through current step */
            int              left_ngood;            /* number of good Ritz pairs on left end */
            int              right_ngood;           /* number of good Ritz pairs on right end */
            int              lastpause;             /* Most recent step with good ritz vecs */
            bool             firstpause;            /* Is this the first pause? */
            bool             nopauses;              /* Have there been any pauses? */
            int              interval;              /* number of steps between pauses */
            double           time;                  /* Current clock time */
            int              left_goodlim;          /* number of ritz pairs checked on left end */
            int              right_goodlim;         /* number of ritz pairs checked on right end */
            double           Anorm;                 /* Norm estimate of the Laplacian matrix */
            int              pausemode;             /* which Lanczos pausing criterion to use */
            bool             pause;                 /* whether to pause */
            int              temp;                  /* used to prevent redundant index computations */
            int *            old_assignment = null; /* set # of each vtx on previous pause, length n+1 */
            int *            assgn_pntr;            /* pntr to assignment vector */
            int *            old_assgn_pntr;        /* pntr to previous assignment vector */
            int              assigndiff;            /* # of differences between old and new assignment */
            int              assigntol;             /* tolerance on convergence of assignment vector */
            bool             ritzval_flag;          /* status flag for get_ritzvals() */
            bool             memory_ok;             /* True until lanczos runs out of memory */
            float *          vwsqrt_float;          /* float version of vwsqrt */

            if (DEBUG_TRACE)
            {
                Trace.WriteLine("<Entering lanczos_so_float>");
            }

            if (DEBUG_EVECS > 0)
            {
                Trace.WriteLine($"Selective orthogonalization Lanczos (v. {version:d}), matrix size = {n:d}.");
            }

            /* Initialize time. */
            time = lanc_seconds();

            if (n < d + 1)
            {
                throw new ArgumentOutOfRangeException(nameof(n), "ERROR: System too small for number of eigenvalues requested.");
                /* d+1 since don't use zero eigenvalue pair */
            }

            /* Allocate space. */
            maxj         = LANCZOS_MAXITNS;
            u            = mkvec_float(1, n);
            u_double     = mkvec(1, n);
            r            = mkvec_float(1, n);
            workn        = mkvec_float(1, n);
            workn_double = mkvec(1, n);
            Ares         = mkvec(0, d);
            index        = (int *)Marshal.AllocHGlobal((d + 1) * sizeof(int));
            alpha        = mkvec(1, maxj);
            beta         = mkvec(0, maxj);
            ritz         = mkvec(1, maxj);
            s            = mkvec(1, maxj);
            bj           = mkvec(1, maxj);
            workj        = mkvec(0, maxj);
            q            = (float **)Marshal.AllocHGlobal((maxj + 1) * sizeof(float *));
            solist       = (orthlink_float **)Marshal.AllocHGlobal((maxj + 1) * sizeof(orthlink_float *));
            scanlist     = mkscanlist(d);
            if (LANCZOS_CONVERGENCE_MODE == 1)
            {
                old_assignment = (int *)Marshal.AllocHGlobal((n + 1) * sizeof(int));
            }

            /* Set some constants governing the orthogonalization heuristic. */
            ngood      = 0;
            maxngood   = 0;
            bji_tol    = eigtol;
            assigntol  = (int)(eigtol * n);
            Anorm      = 2 * maxdeg;                        /* Gershgorin estimate for ||A|| */
            goodtol    = Anorm * Math.Sqrt(DOUBLE_EPSILON); /* Parlett & Scott's bound, p.224 */
            interval   = 2 + Math.Min(LANCZOS_SO_INTERVAL - 2, n / (2 * LANCZOS_SO_INTERVAL));
            bis_safety = BISECTION_SAFETY;

            if (DEBUG_EVECS > 0)
            {
                Trace.WriteLine($"  maxdeg {maxdeg:g}");
                Trace.WriteLine($"  goodtol {goodtol:g}");
                Trace.WriteLine($"  interval {interval:d}");
                Trace.WriteLine($"  maxj {maxj:d}");
                if (LANCZOS_CONVERGENCE_MODE == 1)
                {
                    Trace.WriteLine($"  assigntol {assigntol:d}");
                }
            }

            /* Make a float copy of vwsqrt */
            if (vwsqrt == null)
            {
                vwsqrt_float = null;
            }
            else
            {
                vwsqrt_float = mkvec_float(0, n);
                double_to_float(vwsqrt_float, 1, n, vwsqrt);
            }

            /* Initialize space. */
            vecran_float(r, 1, n);
            if (vwsqrt_float == null)
            {
                orthog1_float(r, 1, n);
            }
            else
            {
                orthogvec_float(r, 1, n, vwsqrt_float);
            }

            beta[0] = norm_float(r, 1, n);
            q[0]    = mkvec_float(1, n);
            setvec_float(q[0], 1, n, 0.0f);
            setvec(bj, 1, maxj, double.MaxValue);

            /* Main Lanczos loop. */
            j              = 1;
            lastpause      = 0;
            pausemode      = 1;
            left_ngood     = 0;
            right_ngood    = 0;
            left_goodlim   = 0;
            right_goodlim  = 0;
            converged      = false;
            Sres_max       = 0.0;
            inc_bis_safety = false;
            ritzval_flag   = false;
            memory_ok      = true;
            firstpause     = false;
            nopauses       = true;
            init_time     += lanc_seconds() - time;
            while ((j <= maxj) && (!converged) && (!ritzval_flag) && memory_ok)
            {
                time = lanc_seconds();

                /* Allocate next Lanczos vector. If fail, back up to last pause. */
                q[j] = mkvec_ret_float(1, n);
                if (q[j] == null)
                {
                    memory_ok = false;
                    if (DEBUG_EVECS > 0 || WARNING_EVECS > 0)
                    {
                        Trace.WriteLine("WARNING: Lanczos out of memory; computing best approximation available.");
                    }

                    if (nopauses)
                    {
                        throw new InvalidOperationException("ERROR: Sorry, can't salvage Lanczos.");
                        /* ... save yourselves, men.  */
                    }

                    for (i = lastpause + 1; i <= j - 1; i++)
                    {
                        frvec_float(q[i], 1);
                    }

                    j = lastpause;
                }

                vecscale_float(q[j], 1, n, (float)(1.0 / beta[j - 1]), r);
                blas_time += lanc_seconds() - time;
                time       = lanc_seconds();
                splarax_float(u, A, n, q[j], vwsqrt_float, workn);
                splarax_time += lanc_seconds() - time;
                time          = lanc_seconds();
                update_float(r, 1, n, u, (float)(-beta[j - 1]), q[j - 1]);
                alpha[j] = dot_float(r, 1, n, q[j]);
                update_float(r, 1, n, r, (float)(-alpha[j]), q[j]);
                blas_time += lanc_seconds() - time;
                time       = lanc_seconds();
                if (vwsqrt_float == null)
                {
                    orthog1_float(r, 1, n);
                }
                else
                {
                    orthogvec_float(r, 1, n, vwsqrt_float);
                }

                if ((j == (lastpause + 1)) || (j == (lastpause + 2)))
                {
                    sorthog_float(r, n, solist, ngood);
                }

                orthog_time += lanc_seconds() - time;
                beta[j]      = norm_float(r, 1, n);
                time         = lanc_seconds();
                pause        = lanpause_float(j, lastpause, interval, q, n, &pausemode, version, beta[j]);
                pause_time  += lanc_seconds() - time;
                if (pause)
                {
                    nopauses = false;
                    if (lastpause == 0)
                    {
                        firstpause = true;
                    }
                    else
                    {
                        firstpause = false;
                    }

                    lastpause = j;

                    /* Compute limits for checking Ritz pair convergence. */
                    if (version == 1)
                    {
                        if (left_ngood + 2 > left_goodlim)
                        {
                            left_goodlim = left_ngood + 2;
                        }

                        if (right_ngood + 3 > right_goodlim)
                        {
                            right_goodlim = right_ngood + 3;
                        }
                    }

                    if (version == 2)
                    {
                        if (left_ngood + 2 > left_goodlim)
                        {
                            left_goodlim = left_ngood + 2;
                        }

                        right_goodlim = 0;
                    }

                    /* Special case: need at least d Ritz vals on left. */
                    left_goodlim = Math.Max(left_goodlim, d);

                    /* Special case: can't find more than j total Ritz vals. */
                    if (left_goodlim + right_goodlim > j)
                    {
                        left_goodlim  = Math.Min(left_goodlim, j);
                        right_goodlim = j - left_goodlim;
                    }

                    /* Find Ritz vals using faster of Sturm bisection or QL. */
                    time       = lanc_seconds();
                    blas_time += lanc_seconds() - time;
                    time       = lanc_seconds();
                    if (inc_bis_safety)
                    {
                        bis_safety    *= 10;
                        inc_bis_safety = false;
                    }

                    ritzval_flag = get_ritzvals(alpha, beta, j, Anorm, workj, ritz, d, left_goodlim,
                                                right_goodlim, eigtol, bis_safety);
                    ql_time += lanc_seconds() - time;

                    /* If get_ritzvals() fails, back up to last pause point and exit main loop. */
                    if (ritzval_flag)
                    {
                        if (DEBUG_EVECS > 0 || WARNING_EVECS > 0)
                        {
                            Trace.WriteLine("ERROR: Lanczos failed in computing eigenvalues of T; computing");
                            Trace.WriteLine("       best readily available approximation to eigenvector.\n");
                        }

                        if (firstpause)
                        {
                            throw new InvalidOperationException("ERROR: Sorry, can't salvage Lanczos.");
                            /* ... save yourselves, men.  */
                        }

                        for (i = lastpause + 1; i <= j; i++)
                        {
                            frvec_float(q[i], 1);
                        }

                        j = lastpause;
                        get_ritzvals(alpha, beta, j, Anorm, workj, ritz, d, left_goodlim, right_goodlim, eigtol,
                                     bis_safety);
                    }

                    /* Scan for minimum evals of tridiagonal. */
                    time = lanc_seconds();
                    scanmin(ritz, 1, j, &scanlist);
                    scan_time += lanc_seconds() - time;

                    /* Compute Ritz pair bounds at left end. */
                    time = lanc_seconds();
                    setvec(bj, 1, j, 0.0);
                    for (i = 1; i <= left_goodlim; i++)
                    {
                        Sres = Tevec(alpha, beta - 1, j, ritz[i], s);
                        if (Sres > Sres_max)
                        {
                            Sres_max = Sres;
                        }

                        if (Sres > SRESTOL)
                        {
                            inc_bis_safety = true;
                        }

                        bj[i] = s[j] * beta[j];
                    }

                    /* Compute Ritz pair bounds at right end. */
                    for (i = j; i > j - right_goodlim; i--)
                    {
                        Sres = Tevec(alpha, beta - 1, j, ritz[i], s);
                        if (Sres > Sres_max)
                        {
                            Sres_max = Sres;
                        }

                        if (Sres > SRESTOL)
                        {
                            inc_bis_safety = true;
                        }

                        bj[i] = s[j] * beta[j];
                    }

                    ritz_time += lanc_seconds() - time;

                    /* Show the portion of the spectrum checked for convergence. */
                    if (DEBUG_EVECS > 2)
                    {
                        time = lanc_seconds();
                        Trace.WriteLine(string.Format("index         Ritz vals            bji bounds   (j = %d)\n", j));
                        for (i = 1; i <= left_goodlim; i++)
                        {
                            Trace.Write($"  {i:d}");
                            doubleout(ritz[i], 1);
                            doubleout(bj[i], 1);
                            Trace.WriteLine("");
                        }

                        Trace.WriteLine("");
                        curlnk = scanlist;
                        while (curlnk != null)
                        {
                            temp = curlnk->indx;
                            if ((temp > left_goodlim) && (temp < j - right_goodlim))
                            {
                                Trace.Write($"  {temp:d}");
                                doubleout(ritz[temp], 1);
                                doubleout(bj[temp], 1);
                                Trace.WriteLine("");
                            }

                            curlnk = curlnk->pntr;
                        }

                        Trace.WriteLine("");
                        for (i = j - right_goodlim + 1; i <= j; i++)
                        {
                            Trace.Write($"  {i:d}");
                            doubleout(ritz[i], 1);
                            doubleout(bj[i], 1);
                            Trace.WriteLine("");
                        }

                        Trace.WriteLine("                            -------------------");
                        Trace.WriteLine(string.Format("                goodtol:    %19.16f\n", goodtol));
                        debug_time += lanc_seconds() - time;
                    }

                    /* Check for convergence. */
                    time = lanc_seconds();
                    if (LANCZOS_CONVERGENCE_MODE != 1 || d > 1)
                    {
                        /* check convergence of residual bound */
                        converged = true;
                        if (j < d)
                        {
                            converged = false;
                        }
                        else
                        {
                            curlnk = scanlist;
                            while (curlnk != null)
                            {
                                if (bj[curlnk->indx] > bji_tol)
                                {
                                    converged = false;
                                }

                                curlnk = curlnk->pntr;
                            }
                        }
                    }

                    if (LANCZOS_CONVERGENCE_MODE == 1 && d == 1)
                    {
                        /* check change in partition */
                        if (firstpause)
                        {
                            converged = true;
                            if (j < d)
                            {
                                converged = false;
                            }
                            else
                            {
                                curlnk = scanlist;
                                while (curlnk != null)
                                {
                                    if (bj[curlnk->indx] > bji_tol)
                                    {
                                        converged = false;
                                    }

                                    curlnk = curlnk->pntr;
                                }
                            }

                            if (!converged)
                            {
                                /* compute current approx. to eigenvectors */
                                i      = d;
                                curlnk = scanlist;
                                while (curlnk != null)
                                {
                                    lambda[i] = curlnk->val;
                                    bound[i]  = bj[curlnk->indx];
                                    index[i]  = curlnk->indx;
                                    curlnk    = curlnk->pntr;
                                    i--;
                                }

                                for (i = 1; i <= d; i++)
                                {
                                    Sres = Tevec(alpha, beta - 1, j, lambda[i], s);
                                    if (Sres > Sres_max)
                                    {
                                        Sres_max = Sres;
                                    }

                                    if (Sres > SRESTOL)
                                    {
                                        inc_bis_safety = true;
                                    }

                                    setvec(y[i], 1, n, 0.0);
                                    for (k = 1; k <= j; k++)
                                    {
                                        scadd_mixed(y[i], 1, n, s[k], q[k]);
                                    }
                                }

                                Assign(A, y, n, d, cube_or_mesh, nsets, vwsqrt, assignment, active, mediantype, goal, vwgt_max);
                            }
                        }
                        else
                        {
                            /* copy assignment to old_assignment */
                            assgn_pntr     = assignment;
                            old_assgn_pntr = old_assignment;
                            for (i = n + 1; i != 0; i--)
                            {
                                *old_assgn_pntr++ = *assgn_pntr++;
                            }

                            /* compute current approx. to eigenvectors */
                            i      = d;
                            curlnk = scanlist;
                            while (curlnk != null)
                            {
                                lambda[i] = curlnk->val;
                                bound[i]  = bj[curlnk->indx];
                                index[i]  = curlnk->indx;
                                curlnk    = curlnk->pntr;
                                i--;
                            }

                            for (i = 1; i <= d; i++)
                            {
                                Sres = Tevec(alpha, beta - 1, j, lambda[i], s);
                                if (Sres > Sres_max)
                                {
                                    Sres_max = Sres;
                                }

                                if (Sres > SRESTOL)
                                {
                                    inc_bis_safety = true;
                                }

                                setvec(y[i], 1, n, 0.0);
                                for (k = 1; k <= j; k++)
                                {
                                    scadd_mixed(y[i], 1, n, s[k], q[k]);
                                }
                            }

                            /* write new assignment */
                            Assign(A, y, n, d, cube_or_mesh, nsets, vwsqrt, assignment, active, mediantype, goal, vwgt_max);

                            assigndiff     = 0;
                            assgn_pntr     = assignment;
                            old_assgn_pntr = old_assignment;
                            for (i = n + 1; i != 0; i--)
                            {
                                if (*old_assgn_pntr++ != *assgn_pntr++)
                                {
                                    assigndiff++;
                                }
                            }

                            assigndiff = Math.Min(assigndiff, n - assigndiff);
                            if (DEBUG_EVECS > 1)
                            {
                                Trace.WriteLine($"  j {j:d},  change from last assignment {assigndiff:d}\n");
                            }

                            if (assigndiff <= assigntol)
                            {
                                converged = true;
                            }
                            else
                            {
                                converged = false;
                            }
                        }
                    }

                    scan_time += lanc_seconds() - time;

                    /* Show current estimates of evals and bounds (for help in tuning) */
                    if (DEBUG_EVECS > 2 && !converged)
                    {
                        time = lanc_seconds();
                        /* Collect eigenvalue and bound information for display, return. */
                        i      = d;
                        curlnk = scanlist;
                        while (curlnk != null)
                        {
                            lambda[i] = curlnk->val;
                            bound[i]  = bj[curlnk->indx];
                            index[i]  = curlnk->indx;
                            curlnk    = curlnk->pntr;
                            i--;
                        }

                        /* Compute eigenvectors and display associated info. */
                        Trace.WriteLine($"j {j:d;}    lambda                Ares est.             Ares          index");
                        for (i = 1; i <= d; i++)
                        {
                            Sres = Tevec(alpha, beta - 1, j, lambda[i], s);
                            if (Sres > Sres_max)
                            {
                                Sres_max = Sres;
                            }

                            if (Sres > SRESTOL)
                            {
                                inc_bis_safety = true;
                            }

                            setvec(y[i], 1, n, 0.0);
                            for (k = 1; k <= j; k++)
                            {
                                scadd_mixed(y[i], 1, n, s[k], q[k]);
                            }

                            float_to_double(u_double, 1, n, u);
                            Ares[i] = checkeig(workn_double, A, y[i], n, lambda[i], vwsqrt, u_double);
                            Trace.Write($"{i:d}.");
                            doubleout(lambda[i], 1);
                            doubleout(bound[i], 1);
                            doubleout(Ares[i], 1);
                            Trace.WriteLine($"   {index[i]:d}");
                        }

                        Trace.WriteLine("");
                        debug_time += lanc_seconds() - time;
                    }

                    if (!converged)
                    {
                        ngood       = 0;
                        left_ngood  = 0; /* for setting left_goodlim on next loop */
                        right_ngood = 0; /* for setting right_goodlim on next loop */

                        /* Compute converged Ritz pairs on left end */
                        time = lanc_seconds();
                        for (i = 1; i <= left_goodlim; i++)
                        {
                            if (bj[i] <= goodtol)
                            {
                                ngood      += 1;
                                left_ngood += 1;
                                if (ngood > maxngood)
                                {
                                    maxngood             = ngood;
                                    solist[ngood]        = makeorthlnk_float();
                                    (solist[ngood])->vec = mkvec_float(1, n);
                                }

                                (solist[ngood])->index = i;
                                Sres = Tevec(alpha, beta - 1, j, ritz[i], s);
                                if (Sres > Sres_max)
                                {
                                    Sres_max = Sres;
                                }

                                if (Sres > SRESTOL)
                                {
                                    inc_bis_safety = true;
                                }

                                setvec_float((solist[ngood])->vec, 1, n, 0.0f);
                                for (k = 1; k <= j; k++)
                                {
                                    scadd_float((solist[ngood])->vec, 1, n, (float)(s[k]), q[k]);
                                }
                            }
                        }

                        /* Compute converged Ritz pairs on right end */
                        for (i = j; i > j - right_goodlim; i--)
                        {
                            if (bj[i] <= goodtol)
                            {
                                ngood       += 1;
                                right_ngood += 1;
                                if (ngood > maxngood)
                                {
                                    maxngood             = ngood;
                                    solist[ngood]        = makeorthlnk_float();
                                    (solist[ngood])->vec = mkvec_float(1, n);
                                }

                                (solist[ngood])->index = i;
                                Sres = Tevec(alpha, beta - 1, j, ritz[i], s);
                                if (Sres > Sres_max)
                                {
                                    Sres_max = Sres;
                                }

                                if (Sres > SRESTOL)
                                {
                                    inc_bis_safety = true;
                                }

                                setvec_float((solist[ngood])->vec, 1, n, 0.0f);
                                for (k = 1; k <= j; k++)
                                {
                                    scadd_float((solist[ngood])->vec, 1, n, (float)(s[k]), q[k]);
                                }
                            }
                        }

                        ritz_time += lanc_seconds() - time;

                        if (DEBUG_EVECS > 2)
                        {
                            time = lanc_seconds();
                            Trace.Write($"  j {j:d}; goodlim lft {left_goodlim:d}, rgt {right_goodlim:d}; list ");
                            solistout_float(solist, ngood, j);
                            Trace.WriteLine("---------------------end of iteration---------------------\n");
                            debug_time += lanc_seconds() - time;
                        }
                    }
                }

                j++;
            }

            j--;

            /* Collect eigenvalue and bound information. Only compute and display info for
             * the eigpairs actually used in the partitioning since don't want to spend the
             * time or space to compute the null-space of the Laplacian. */
            time   = lanc_seconds();
            i      = d;
            curlnk = scanlist;
            while (curlnk != null)
            {
                lambda[i] = curlnk->val;
                bound[i]  = bj[curlnk->indx];
                index[i]  = curlnk->indx;
                curlnk    = curlnk->pntr;
                i--;
            }

            scan_time += lanc_seconds() - time;

            /* Compute eigenvectors. */
            time = lanc_seconds();
            for (i = 1; i <= d; i++)
            {
                Sres = Tevec(alpha, beta - 1, j, lambda[i], s);
                if (Sres > Sres_max)
                {
                    Sres_max = Sres;
                }

                setvec(y[i], 1, n, 0.0);
                for (k = 1; k <= j; k++)
                {
                    scadd_mixed(y[i], 1, n, s[k], q[k]);
                }
            }

            evec_time += lanc_seconds() - time;

            time = lanc_seconds();
            float_to_double(u_double, 1, n, u);
            warnings(workn_double, A, y, n, lambda, vwsqrt, Ares, bound, index, d, j, maxj, Sres_max, eigtol,
                     u_double, Anorm);
            debug_time += lanc_seconds() - time;

            /* free up memory */
            time = lanc_seconds();
            frvec_float(u, 1);
            frvec(u_double, 1);
            frvec_float(r, 1);
            frvec_float(workn, 1);
            frvec(workn_double, 1);
            frvec(Ares, 0);
            Marshal.FreeHGlobal((IntPtr)index);
            frvec(alpha, 1);
            frvec(beta, 0);
            frvec(ritz, 1);
            frvec(s, 1);
            frvec(bj, 1);
            frvec(workj, 0);
            for (i = 0; i <= j; i++)
            {
                frvec_float(q[i], 1);
            }

            Marshal.FreeHGlobal((IntPtr)q);
            if (vwsqrt_float != null)
            {
                frvec_float(vwsqrt_float, 0);
            }

            while (scanlist != null)
            {
                curlnk = scanlist->pntr;
                Marshal.FreeHGlobal((IntPtr)scanlist);
                scanlist = curlnk;
            }

            for (i = 1; i <= maxngood; i++)
            {
                frvec_float((solist[i])->vec, 1);
                Marshal.FreeHGlobal((IntPtr)solist[i]);
            }

            Marshal.FreeHGlobal((IntPtr)solist);
            if (LANCZOS_CONVERGENCE_MODE == 1)
            {
                Marshal.FreeHGlobal((IntPtr)old_assignment);
            }

            init_time += lanc_seconds() - time;
        }
Exemple #30
0
        /* Confirm that the bipartite match algorithm did the right thing. */
        public static void checkbp(
            vtx_data **graph, /* graph data structure for vertex weights */
            double *[] xvecs, /* values to partition */
            int *sets,        /* set assignments returned */
            double[] dists,   /* distances that separate sets */
            int nvtxs,        /* number of vertices */
            int ndims         /* number of dimensions for division */
            )
        {
            int[]        signs = new int[MAXDIMS];   /* signs for coordinates of target points */
            int[]        sizes = new int[MAXSETS];   /* size of each set */
            int[]        weights = new int[MAXSETS]; /* size of each set */
            double       setval = 0.0;               /* value from assigned set */
            double       val, bestval = 0.0;         /* value to decide set assignment */
            const double tolerance = 1.0e-8;         /* numerical tolerance */
            bool         error     = false;          /* are errors encountered? */
            int          bestset   = -1;             /* set vtx should be assigned to */

            var nsets = 1 << ndims;                  /* number of sets */

            for (var i = 0; i < nsets; i++)
            {
                sizes[i]   = 0;
                weights[i] = 0;
            }

            for (var i = 1; i <= nvtxs; i++)
            {
                /* Is vertex closest to the set it is assigned to? */
                for (var j = 0; j < MAXDIMS; j++)
                {
                    signs[j] = -1;
                }

                bestval = 0;
                for (var j = 0; j < nsets; j++)
                {
                    val = -dists[j];
                    for (var k = 1; k <= ndims; k++)
                    {
                        val += 2 * signs[k - 1] * xvecs[k][i];
                    }

                    if (j == sets[i])
                    {
                        setval = val;
                    }

                    if (j == 0 || val < bestval)
                    {
                        bestval = val;
                        bestset = j;
                    }

                    if (signs[0] == 1 && signs[1] == 1)
                    {
                        signs[2] *= -1;
                    }

                    if (signs[0] == 1)
                    {
                        signs[1] *= -1;
                    }

                    signs[0] *= -1;
                }

                if (Math.Abs(setval - bestval) >= tolerance * (Math.Abs(setval) + Math.Abs(bestval)))
                {
                    Trace.WriteLine($" Vtx {i:d} in set {sets[i]:d} ({setval:e}), but should be in {bestset:d} ({bestval:e})");
                    error = true;
                }

                ++sizes[sets[i]];
                weights[sets[i]] += graph[i]->vwgt;
            }

            Console.Write(" Sizes:");
            for (var i = 0; i < nsets; i++)
            {
                Console.Write(" {0:d}({1:d})", sizes[i], weights[i]);
            }

            Trace.WriteLine("");

            if (error)
            {
                throw new InvalidOperationException("ERROR in checkbp");
            }
        }