/* Once, or iteratively? */ public static void coarsen_klv( /* Coarsen until nvtxs < vmax, compute and uncoarsen. */ vtx_data **graph, /* array of vtx data for graph */ int nvtxs, /* number of vertices in graph */ int nedges, /* number of edges in graph */ bool using_vwgts, /* are vertices weights being used? */ bool useEdgeWeights, /* are edge weights being used? */ float *[] term_wgts, /* weights for terminal propagation */ int igeom, /* dimension for geometric information */ float **coords, /* coordinates for vertices */ int vwgt_max, /* largest vertex weight */ int *assignment, /* processor each vertex gets assigned to */ double [] goal, /* desired set sizes */ int architecture, /* 0 => hypercube, d => d-dimensional mesh */ int [][] hops, /* cost of edge between sets */ LanczosType solver_flag, /* which eigensolver to use */ int ndims, /* number of eigenvectors to calculate */ int nsets, /* number of sets being divided into */ int vmax, /* largest subgraph to stop coarsening */ MappingType mediantype, /* flag for different assignment strategies */ bool mkconnected, /* enforce connectivity before eigensolve? */ double eigtol, /* tolerance in eigen calculation */ int nstep, /* number of coarsenings between RQI steps */ int step, /* current step number */ int **pbndy_list, /* pointer to returned boundary list */ double[] weights, /* weights of vertices in each set */ bool give_up /* has coarsening bogged down? */ ) { vtx_data **cgraph = null; /* array of vtx data for coarsened graph */ double[] new_goal = new double[MAXSETS]; /* new goal if not using vertex weights */ double [] real_goal; /* chooses between goal and new_goal */ double total_weight; /* total weight of vertices */ double goal_weight; /* total weight of vertices in goal */ float *[] cterm_wgts = new float *[MAXSETS]; /* terminal weights for coarse graph */ float *[] new_term_wgts = new float *[MAXSETS]; /* modified for Bui's method */ float *[] real_term_wgts; /* which of previous two to use */ float ewgt_max; /* largest edge weight in graph */ float * twptr = null; /* loops through term_wgts */ float * twptr_save = null; /* copy of twptr */ float * ctwptr; /* loops through cterm_wgts */ float ** ccoords; /* coarse graph coordinates */ int * v2cv = null; /* mapping from vtxs to coarse vtxs */ bool * flag; /* scatter array for coarse bndy vtxs */ int * bndy_list; /* list of vertices on boundary */ int * cbndy_list = null; /* list of vertices of coarse graph on boundary */ int * cassignment; /* set assignments for coarsened vertices */ bool flattened; /* was this graph flattened? */ int list_length; /* length of boundary vtx list */ int cnvtxs = 0; /* number of vertices in coarsened graph */ int cnedges = 0; /* number of edges in coarsened graph */ int cvwgt_max; /* largest vertex weight in coarsened graph */ int nextstep; /* next step in RQI test */ int max_dev; /* largest allowed deviation from balance */ int i, j; /* loop counters */ if (DEBUG_COARSEN || DEBUG_TRACE) { Trace.WriteLine($"<Entering coarsen_kl, {nameof(step)}={step:d}, {nameof(nvtxs)}={nvtxs:d}, {nameof(nedges)}={nedges:d}, {nameof(vmax)}={vmax:d}>\n"); } /* Is problem small enough to solve? */ if (nvtxs <= vmax || give_up) { real_goal = goal; simple_part(graph, nvtxs, assignment, nsets, MappingType.MinCost, real_goal); list_length = find_bndy(graph, nvtxs, assignment, 2, &bndy_list); count_weights(graph, nvtxs, assignment, nsets + 1, weights, true); max_dev = (step == 0) ? vwgt_max : 5 * vwgt_max; total_weight = 0; for (i = 0; i < nsets; i++) { total_weight += real_goal[i]; } if (max_dev > total_weight) { max_dev = vwgt_max; } goal_weight = total_weight * KL_IMBALANCE / nsets; if (goal_weight > max_dev) { max_dev = (int)goal_weight; } if (COARSE_KLV) { klvspiff(graph, nvtxs, assignment, real_goal, max_dev, &bndy_list, weights); } if (COARSE_BPM) { bpm_improve(graph, assignment, real_goal, max_dev, &bndy_list, weights, using_vwgts); } *pbndy_list = bndy_list; return; } /* Otherwise I have to coarsen. */ flattened = false; if (coords != null) { ccoords = (float **)Marshal.AllocHGlobal(igeom * sizeof(float *)); } else { ccoords = null; } if (FLATTEN && step == 0) { flattened = flatten(graph, nvtxs, nedges, &cgraph, &cnvtxs, &cnedges, &v2cv, useEdgeWeights && COARSEN_EWGTS, igeom, coords, ccoords); } if (!flattened) { coarsen1(graph, nvtxs, nedges, &cgraph, &cnvtxs, &cnedges, &v2cv, igeom, coords, ccoords, useEdgeWeights && COARSEN_EWGTS); } if (term_wgts[1] != null) { twptr = (float *)Marshal.AllocHGlobal((cnvtxs + 1) * (nsets - 1) * sizeof(float)); twptr_save = twptr; for (i = (cnvtxs + 1) * (nsets - 1); i != 0; i--) { *twptr++ = 0; } twptr = twptr_save; for (j = 1; j < nsets; j++) { cterm_wgts[j] = twptr; twptr += cnvtxs + 1; } for (j = 1; j < nsets; j++) { ctwptr = cterm_wgts[j]; twptr = term_wgts[j]; for (i = 1; i < nvtxs; i++) { ctwptr[v2cv[i]] += twptr[i]; } } } else { cterm_wgts[1] = null; } /* If coarsening isn't working very well, give up and partition. */ give_up = false; if (nvtxs * COARSEN_RATIO_MIN < cnvtxs && cnvtxs > vmax && !flattened) { Trace.WriteLine($"WARNING: Coarsening not making enough progress, {nameof(nvtxs)} = {nvtxs:d}, {nameof(cnvtxs)} = {cnvtxs:d}."); Trace.WriteLine(" Recursive coarsening being stopped prematurely."); give_up = true; } /* Now recurse on coarse subgraph. */ if (COARSEN_VWGTS) { cvwgt_max = 0; for (i = 1; i <= cnvtxs; i++) { if (cgraph[i]->vwgt > cvwgt_max) { cvwgt_max = cgraph[i]->vwgt; } } } else { cvwgt_max = 1; } cassignment = (int *)Marshal.AllocHGlobal((cnvtxs + 1) * sizeof(int)); if (flattened) { nextstep = step; } else { nextstep = step + 1; } coarsen_klv(cgraph, cnvtxs, cnedges, COARSEN_VWGTS, COARSEN_EWGTS, cterm_wgts, igeom, ccoords, cvwgt_max, cassignment, goal, architecture, hops, solver_flag, ndims, nsets, vmax, mediantype, mkconnected, eigtol, nstep, nextstep, &cbndy_list, weights, give_up); /* Interpolate assignment back to fine graph. */ for (i = 1; i <= nvtxs; i++) { assignment[i] = cassignment[v2cv[i]]; } /* Construct boundary list from coarse boundary list. */ flag = (bool *)Marshal.AllocHGlobal((cnvtxs + 1) * sizeof(bool)); for (i = 1; i <= cnvtxs; i++) { flag[i] = false; } for (i = 0; cbndy_list[i] != 0; i++) { flag[cbndy_list[i]] = true; } list_length = 0; for (i = 1; i <= nvtxs; i++) { if (flag[v2cv[i]]) { ++list_length; } } bndy_list = (int *)Marshal.AllocHGlobal((list_length + 1) * sizeof(int)); list_length = 0; for (i = 1; i <= nvtxs; i++) { if (flag[v2cv[i]]) { bndy_list[list_length++] = i; } } bndy_list[list_length] = 0; Marshal.FreeHGlobal((IntPtr)flag); Marshal.FreeHGlobal((IntPtr)cbndy_list); /* Free the space that was allocated. */ Marshal.FreeHGlobal((IntPtr)cassignment); if (twptr_save != null) { Marshal.FreeHGlobal((IntPtr)twptr_save); twptr_save = null; } free_graph(cgraph); Marshal.FreeHGlobal((IntPtr)v2cv); /* Smooth using KL or BPM every nstep steps. */ if ((step % nstep) == 0 && !flattened) { if (!COARSEN_VWGTS && step != 0) /* Construct new goal */ { goal_weight = 0; for (i = 0; i < nsets; i++) { goal_weight += goal[i]; } for (i = 0; i < nsets; i++) { new_goal[i] = goal[i] * (nvtxs / goal_weight); } real_goal = new_goal; } else { real_goal = goal; } if (LIMIT_KL_EWGTS) { find_maxdeg(graph, nvtxs, useEdgeWeights, &ewgt_max); compress_ewgts(graph, nvtxs, nedges, ewgt_max, useEdgeWeights); } /* If not coarsening ewgts, then need care with term_wgts. */ if (!useEdgeWeights && term_wgts[1] != null && step != 0) { twptr = (float *)Marshal.AllocHGlobal((nvtxs + 1) * (nsets - 1) * sizeof(float)); twptr_save = twptr; for (j = 1; j < nsets; j++) { new_term_wgts[j] = twptr; twptr += nvtxs + 1; } for (j = 1; j < nsets; j++) { twptr = term_wgts[j]; ctwptr = new_term_wgts[j]; for (i = 1; i <= nvtxs; i++) { if (twptr[i] > .5) { ctwptr[i] = 1; } else if (twptr[i] < -.5) { ctwptr[i] = -1; } else { ctwptr[i] = 0; } } } real_term_wgts = new_term_wgts; } else { real_term_wgts = term_wgts; new_term_wgts[1] = null; } max_dev = (step == 0) ? vwgt_max : 5 * vwgt_max; total_weight = 0; for (i = 0; i < nsets; i++) { total_weight += real_goal[i]; } if (max_dev > total_weight) { max_dev = vwgt_max; } goal_weight = total_weight * KL_IMBALANCE / nsets; if (goal_weight > max_dev) { max_dev = (int)goal_weight; } if (!COARSEN_VWGTS) { count_weights(graph, nvtxs, assignment, nsets + 1, weights, (vwgt_max != 1)); } if (COARSE_KLV) { klvspiff(graph, nvtxs, assignment, real_goal, max_dev, &bndy_list, weights); } if (COARSE_BPM) { bpm_improve(graph, assignment, real_goal, max_dev, &bndy_list, weights, using_vwgts); } if (real_term_wgts != term_wgts && new_term_wgts[1] != null) { Marshal.FreeHGlobal((IntPtr)real_term_wgts[1]); } if (LIMIT_KL_EWGTS) { restore_ewgts(graph, nvtxs); } } *pbndy_list = bndy_list; if (twptr_save != null) { Marshal.FreeHGlobal((IntPtr)twptr_save); } /* Free the space that was allocated. */ if (ccoords != null) { for (i = 0; i < igeom; i++) { Marshal.FreeHGlobal((IntPtr)ccoords[i]); } Marshal.FreeHGlobal((IntPtr)ccoords); } if (DEBUG_COARSEN) { Trace.WriteLine($" Leaving coarsen_klv, {nameof(step)}={step:d}"); } }
public static void coarsen( /* Coarsen until nvtxs <= vmax, compute and uncoarsen. */ vtx_data **graph, /* array of vtx data for graph */ int nvtxs, /* number of vertices in graph */ int nedges, /* number of edges in graph */ bool using_vwgts, /* are vertices weights being used? */ bool useEdgeWeights, /* are edge weights being used? */ float *[] term_wgts, /* terminal weights */ int igeom, /* dimension for geometric information */ float **coords, /* coordinates for vertices */ double *[] yvecs, /* eigenvectors returned */ int ndims, /* number of eigenvectors to calculate */ LanczosType solver_flag, /* which eigensolver to use */ int vmax, /* largest subgraph to stop coarsening */ double eigtol, /* tolerance in eigen calculation */ int nstep, /* number of coarsenings between RQI steps */ int step, /* current step number */ bool give_up /* has coarsening bogged down? */ ) { vtx_data **cgraph; /* array of vtx data for coarsened graph */ orthlink * orthlist; /* list of lower evecs to suppress */ orthlink * newlink; /* lower evec to suppress */ double *[] cyvecs = new double *[MAXDIMS + 1]; /* eigenvectors for subgraph */ double[] evals = new double[MAXDIMS + 1]; /* eigenvalues returned */ double[] goal = new double[MAXSETS]; /* needed for convergence mode = 1 */ double * r1; /* space needed by symmlq/RQI */ double * r2; /* space needed by symmlq/RQI */ double * work; /* space needed by symmlq/RQI */ double * v; /* space needed by symmlq/RQI */ double * w; /* space needed by symmlq/RQI */ double * x; /* space needed by symmlq/RQI */ double * y; /* space needed by symmlq/RQI */ double * gvec; /* rhs vector in extended eigenproblem */ double evalest; /* eigenvalue estimate returned by RQI */ double maxdeg; /* maximum weighted degree of a vertex */ float ** ccoords; /* coordinates for coarsened graph */ float *[] cterm_wgts = new float *[MAXSETS]; /* coarse graph terminal weights */ float *[] new_term_wgts = new float *[MAXSETS]; /* terminal weights for Bui's method*/ float *[] real_term_wgts; /* one of the above */ float * twptr = null; /* loops through term_wgts */ float * twptr_save = null; /* copy of twptr */ float * ctwptr; /* loops through cterm_wgts */ double * vwsqrt = null; /* square root of vertex weights */ double norm, alpha; /* values used for orthogonalization */ double initshift; /* initial shift for RQI */ double total_vwgt; /* sum of all the vertex weights */ double w1, w2; /* weights of two sets */ double term_tot; /* sum of all terminal weights */ int * space; /* room for assignment in Lanczos */ int * morespace; /* room for assignment in Lanczos */ int * v2cv; /* mapping from vertices to coarse vtxs */ int vwgt_max; /* largest vertex weight */ bool oldperturb; /* saves PERTURB value */ int cnvtxs; /* number of vertices in coarsened graph */ int cnedges; /* number of edges in coarsened graph */ int nextstep; /* next step in RQI test */ int nsets; /* number of sets being created */ int i, j; /* loop counters */ double time; /* time marker */ if (DEBUG_COARSEN) { Trace.WriteLine($"<Entering coarsen, {nameof(step)}={step:D}, {nameof(nvtxs)}={nvtxs:D}, {nameof(nedges)}={nedges:D}, {nameof(vmax)}={vmax:D}>\n"); } nsets = 1 << ndims; /* Is problem small enough to solve? */ if (nvtxs <= vmax || give_up) { if (using_vwgts) { vwsqrt = (double *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(double)); makevwsqrt(vwsqrt, graph, nvtxs); } else { vwsqrt = null; } maxdeg = find_maxdeg(graph, nvtxs, useEdgeWeights, null); if (using_vwgts) { vwgt_max = 0; total_vwgt = 0; for (i = 1; i <= nvtxs; i++) { if (graph[i]->vwgt > vwgt_max) { vwgt_max = graph[i]->vwgt; } total_vwgt += graph[i]->vwgt; } } else { vwgt_max = 1; total_vwgt = nvtxs; } for (i = 0; i < nsets; i++) { goal[i] = total_vwgt / nsets; } space = (int *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(int)); /* If not coarsening ewgts, then need care with term_wgts. */ if (!useEdgeWeights && term_wgts[1] != null && step != 0) { twptr = (float *)Marshal.AllocHGlobal((nvtxs + 1) * (nsets - 1) * sizeof(float)); twptr_save = twptr; for (j = 1; j < nsets; j++) { new_term_wgts[j] = twptr; twptr += nvtxs + 1; } for (j = 1; j < nsets; j++) { twptr = term_wgts[j]; ctwptr = new_term_wgts[j]; for (i = 1; i <= nvtxs; i++) { if (twptr[i] > .5) { ctwptr[i] = 1; } else if (twptr[i] < -.5) { ctwptr[i] = -1; } else { ctwptr[i] = 0; } } } real_term_wgts = new_term_wgts; } else { real_term_wgts = term_wgts; new_term_wgts[1] = null; } eigensolve(graph, nvtxs, nedges, maxdeg, vwgt_max, vwsqrt, using_vwgts, useEdgeWeights, real_term_wgts, igeom, coords, yvecs, evals, false, space, goal, solver_flag, false, 0, ndims, MappingType.IndependantMedians, eigtol); if (real_term_wgts != term_wgts && new_term_wgts[1] != null) { Marshal.FreeHGlobal((IntPtr)real_term_wgts[1]); } Marshal.FreeHGlobal((IntPtr)space); space = null; Marshal.FreeHGlobal((IntPtr)vwsqrt); vwsqrt = null; Marshal.FreeHGlobal((IntPtr)twptr_save); twptr_save = null; return; } /* Otherwise I have to coarsen. */ if (coords != null) { ccoords = (float **)Marshal.AllocHGlobal(igeom * sizeof(float *)); } else { ccoords = null; } coarsen1(graph, nvtxs, nedges, &cgraph, &cnvtxs, &cnedges, &v2cv, igeom, coords, ccoords, useEdgeWeights); /* If coarsening isn't working very well, give up and partition. */ give_up = false; if (nvtxs * COARSEN_RATIO_MIN < cnvtxs && cnvtxs > vmax) { Trace.WriteLine($"WARNING: Coarsening not making enough progress, {nameof(nvtxs)} = {nvtxs:d}, {nameof(cnvtxs)} = {cnvtxs:d}."); Trace.WriteLine(" Recursive coarsening being stopped prematurely."); give_up = true; } /* Create space for subgraph yvecs. */ for (i = 1; i <= ndims; i++) { cyvecs[i] = (double *)Marshal.AllocHGlobal((cnvtxs + 1) * sizeof(double)); } /* Make coarse version of terminal weights. */ if (term_wgts[1] != null) { twptr = (float *)Marshal.AllocHGlobal((cnvtxs + 1) * (nsets - 1) * sizeof(float)); twptr_save = twptr; for (i = (cnvtxs + 1) * (nsets - 1); i != 0; i--) { *twptr++ = 0; } twptr = twptr_save; for (j = 1; j < nsets; j++) { cterm_wgts[j] = twptr; twptr += cnvtxs + 1; } for (j = 1; j < nsets; j++) { ctwptr = cterm_wgts[j]; twptr = term_wgts[j]; for (i = 1; i < nvtxs; i++) { ctwptr[v2cv[i]] += twptr[i]; } } } else { cterm_wgts[1] = null; } /* Now recurse on coarse subgraph. */ nextstep = step + 1; coarsen(cgraph, cnvtxs, cnedges, COARSEN_VWGTS, COARSEN_EWGTS, cterm_wgts, igeom, ccoords, cyvecs, ndims, solver_flag, vmax, eigtol, nstep, nextstep, give_up); ch_interpolate(yvecs, cyvecs, ndims, graph, nvtxs, v2cv, useEdgeWeights); Marshal.FreeHGlobal((IntPtr)twptr_save); twptr_save = null; Marshal.FreeHGlobal((IntPtr)v2cv); v2cv = null; /* I need to do Rayleigh Quotient Iteration each nstep stages. */ time = seconds(); if ((step % nstep) == 0) { oldperturb = PERTURB; PERTURB = false; /* Should I do some orthogonalization here against vwsqrt? */ if (using_vwgts) { vwsqrt = (double *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(double)); makevwsqrt(vwsqrt, graph, nvtxs); for (i = 1; i <= ndims; i++) { orthogvec(yvecs[i], 1, nvtxs, vwsqrt); } } else { for (i = 1; i <= ndims; i++) { orthog1(yvecs[i], 1, nvtxs); } } /* Allocate space that will be needed in RQI. */ r1 = (double *)Marshal.AllocHGlobal(7 * (nvtxs + 1) * sizeof(double)); r2 = &r1[nvtxs + 1]; v = &r1[2 * (nvtxs + 1)]; w = &r1[3 * (nvtxs + 1)]; x = &r1[4 * (nvtxs + 1)]; y = &r1[5 * (nvtxs + 1)]; work = &r1[6 * (nvtxs + 1)]; if (using_vwgts) { vwgt_max = 0; total_vwgt = 0; for (i = 1; i <= nvtxs; i++) { if (graph[i]->vwgt > vwgt_max) { vwgt_max = graph[i]->vwgt; } total_vwgt += graph[i]->vwgt; } } else { vwgt_max = 1; total_vwgt = nvtxs; } for (i = 0; i < nsets; i++) { goal[i] = total_vwgt / nsets; } space = (int *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(int)); morespace = (int *)Marshal.AllocHGlobal((nvtxs) * sizeof(int)); initshift = 0; orthlist = null; for (i = 1; i < ndims; i++) { ch_normalize(yvecs[i], 1, nvtxs); rqi(graph, yvecs, i, nvtxs, r1, r2, v, w, x, y, work, eigtol, initshift, &evalest, vwsqrt, orthlist, false, nsets, space, morespace, MappingType.IndependantMedians, goal, vwgt_max, ndims); /* Now orthogonalize higher yvecs against this one. */ norm = dot(yvecs[i], 1, nvtxs, yvecs[i]); for (j = i + 1; j <= ndims; j++) { alpha = -dot(yvecs[j], 1, nvtxs, yvecs[i]) / norm; scadd(yvecs[j], 1, nvtxs, alpha, yvecs[i]); } /* Now prepare for next pass through loop. */ initshift = evalest; newlink = makeorthlnk(); newlink->vec = yvecs[i]; newlink->pntr = orthlist; orthlist = newlink; } ch_normalize(yvecs[ndims], 1, nvtxs); if (term_wgts[1] != null && ndims == 1) { /* Solve extended eigen problem */ /* If not coarsening ewgts, then need care with term_wgts. */ if (!useEdgeWeights && term_wgts[1] != null && step != 0) { twptr = (float *)Marshal.AllocHGlobal((nvtxs + 1) * (nsets - 1) * sizeof(float)); twptr_save = twptr; for (j = 1; j < nsets; j++) { new_term_wgts[j] = twptr; twptr += nvtxs + 1; } for (j = 1; j < nsets; j++) { twptr = term_wgts[j]; ctwptr = new_term_wgts[j]; for (i = 1; i <= nvtxs; i++) { if (twptr[i] > .5) { ctwptr[i] = 1; } else if (twptr[i] < -.5) { ctwptr[i] = -1; } else { ctwptr[i] = 0; } } } real_term_wgts = new_term_wgts; } else { real_term_wgts = term_wgts; new_term_wgts[1] = null; } /* Following only works for bisection. */ w1 = goal[0]; w2 = goal[1]; gvec = (double *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(double)); term_tot = 0; for (j = 1; j <= nvtxs; j++) { term_tot += (real_term_wgts[1])[j]; } term_tot /= (w1 + w2); if (using_vwgts) { for (j = 1; j <= nvtxs; j++) { gvec[j] = (real_term_wgts[1])[j] / graph[j]->vwgt - term_tot; } } else { for (j = 1; j <= nvtxs; j++) { gvec[j] = (real_term_wgts[1])[j] - term_tot; } } rqi_ext(); Marshal.FreeHGlobal((IntPtr)gvec); gvec = null; if (real_term_wgts != term_wgts && new_term_wgts[1] != null) { Marshal.FreeHGlobal((IntPtr)new_term_wgts[1]); new_term_wgts[1] = null; } } else { rqi(graph, yvecs, ndims, nvtxs, r1, r2, v, w, x, y, work, eigtol, initshift, &evalest, vwsqrt, orthlist, false, nsets, space, morespace, MappingType.IndependantMedians, goal, vwgt_max, ndims); } refine_time += seconds() - time; /* Free the space allocated for RQI. */ Marshal.FreeHGlobal((IntPtr)morespace); Marshal.FreeHGlobal((IntPtr)space); while (orthlist != null) { newlink = orthlist->pntr; Marshal.FreeHGlobal((IntPtr)orthlist); orthlist = newlink; } Marshal.FreeHGlobal((IntPtr)r1); Marshal.FreeHGlobal((IntPtr)vwsqrt); vwsqrt = null; PERTURB = oldperturb; } if (DEBUG_COARSEN) { Trace.WriteLine($" Leaving coarsen, {nameof(step)}={step:d}"); } Marshal.FreeHGlobal((IntPtr)twptr_save); twptr_save = null; /* Free the space that was allocated. */ if (ccoords != null) { for (i = 0; i < igeom; i++) { Marshal.FreeHGlobal((IntPtr)ccoords[i]); } Marshal.FreeHGlobal((IntPtr)ccoords); } for (i = ndims; i > 0; i--) { Marshal.FreeHGlobal((IntPtr)cyvecs[i]); } free_graph(cgraph); }
/* Invoke the eigenvector calculation */ public static void eigensolve(vtx_data **graph, /* graph data structure */ int nvtxs, /* number of vertices in graph */ int nedges, /* number of edges in graph */ double maxdeg, /* largest (weighted) degree of a vertex */ int vwgt_max, /* largest vertex weight */ double *vwsqrt, /* sqrt of vertex weights (length nvtxs+1) */ bool using_vwgts, /* are vertex weights being used? */ bool useEdgeWeights, /* are edge weights being used? */ float *[] term_wgts, /* terminal propagation weight vector */ int igeom, /* geometric dimensionality if given coords */ float **coords, /* coordinates of vertices */ double *[] yvecs, /* space for pointing to eigenvectors */ double[] evals, /* eigenvalues associated with eigenvectors */ bool architecture, /* 0 => hypercube, d => d-dimensional mesh */ int *assignment, /* set number of each vtx (length n+1) */ double[] goal, /* desired set sizes */ LanczosType solver_flag, /* flag indicating which solver to use */ bool rqi_flag, /* use multi-level techniques? */ int vmax, /* if so, how many vtxs to coarsen down to? */ int ndims, /* number of eigenvectors (2^d sets) */ MappingType mediantype, /* which partitioning strategy to use */ double eigtol /* tolerance on eigenvectors */ ) { double[] bound = new double[MAXDIMS + 1]; /* ritz approx bounds to eigenpairs */ double time; /* time marker */ float *[] dummy_twgt = new float *[2]; /* turns off terminal propagation */ float * twptr; /* terminal propagation weight vector */ int * active; /* space for nvtxs values */ int step; /* current step in RQI counting */ int nstep; /* number of uncoarsening levels between RQIs */ int version; /* which version of sel. orth. to use */ int nsets = 0; /* number of sets to divide into */ double * g; /* rhs n-vector in the extended eigenproblem */ double * ptr; /* loops through yvec */ double w1, w2; /* desired weights of two sets */ double term_tot; /* sum of terminal weights */ double sigma; /* norm constraint on extended eigenvector */ int i, j; /* loop counter */ bool normal; /* use normal or extended eigensolver? */ bool autoset_maxitns; /* set LANCZOS_MAXITNS automatically? */ int prev_maxitns = 0; /* LANCZOS_MAXITNS value above this routine */ bool autoset_srestol; /* set SRESTOL automatically? */ double prev_srestol = 0; /* SRESTOL value above this routine */ if (DEBUG_TRACE) { Trace.WriteLine($"<Entering eigensolve, nvtxs = {nvtxs:d}, nedges ={nedges:d}>\n"); } if (nvtxs <= ndims) { /* Pathological special case. */ for (i = 1; i <= ndims; i++) { for (j = 1; j <= nvtxs; j++) { yvecs[i][j] = 0; } } return; } active = null; /* Autoset (if necessary) some parameters for the eigen calculation */ autoset_maxitns = false; autoset_srestol = false; if (LANCZOS_MAXITNS < 0) { autoset_maxitns = true; prev_maxitns = LANCZOS_MAXITNS; LANCZOS_MAXITNS = 2 * nvtxs; } if (SRESTOL < 0) { autoset_srestol = true; prev_srestol = SRESTOL; SRESTOL = eigtol * eigtol; } /* Note: When (if ever) rqi_ext is done, change precedence of eigensolvers. */ if (term_wgts[1] != null && ndims == 1) { /* then use lanczos_ext */ if (PERTURB) { if (NPERTURB > 0 && PERTURB_MAX > 0.0) { perturb_init(nvtxs); if (DEBUG_PERTURB) { Trace.WriteLine($"Matrix being perturbed with scale {PERTURB_MAX:E}\n"); } } else if (DEBUG_PERTURB) { Trace.WriteLine("Matrix not being perturbed\n"); } } version = 2; if (LANCZOS_CONVERGENCE_MODE == 1) { active = (int *)Marshal.AllocHGlobal(nvtxs * sizeof(int)); } w1 = goal[0]; w2 = goal[1]; sigma = Math.Sqrt(4 * w1 * w2 / (w1 + w2)); g = (double *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(double)); twptr = term_wgts[1]; term_tot = 0; for (i = 1; i <= nvtxs; i++) { term_tot += twptr[i]; } term_tot /= (w1 + w2); if (using_vwgts) { for (i = 1; i <= nvtxs; i++) { g[i] = twptr[i] / graph[i]->vwgt - term_tot; } } else { for (i = 1; i <= nvtxs; i++) { g[i] = twptr[i] - term_tot; } } time = seconds(); if (LANCZOS_SO_PRECISION == 2) { /* double precision */ normal = lanczos_ext(graph, nvtxs, ndims, yvecs, eigtol, vwsqrt, maxdeg, version, g, sigma); } else { /* single precision */ normal = lanczos_ext_float(graph, nvtxs, ndims, yvecs, eigtol, vwsqrt, maxdeg, version, g, sigma); } Marshal.FreeHGlobal((IntPtr)g); if (active != null) { Marshal.FreeHGlobal((IntPtr)(active)); } active = null; if (normal) { if (WARNING_EVECS > 2) { Trace.WriteLine("WARNING: Not an extended eigenproblem; switching to standard eigensolver.\n"); } } else { if (w2 != w1) { if (using_vwgts) { y2x(yvecs, ndims, nvtxs, vwsqrt); } sigma = (w2 - w1) / (w2 + w1); ptr = yvecs[1]; for (i = nvtxs; i != 0; i--) { *(++ptr) += sigma; } /* Note: if assign() could skip scaling, next call unnecessary. */ if (using_vwgts) { x2y(yvecs, ndims, nvtxs, vwsqrt); } } } if (PERTURB && NPERTURB > 0 && PERTURB_MAX > 0.0) { perturb_clear(); } lanczos_time += seconds() - time; } else { normal = true; } if (normal) { if (rqi_flag) { /* Solve using multi-level scheme RQI/Symmlq. */ time = seconds(); nstep = COARSE_NLEVEL_RQI; step = 0; dummy_twgt[1] = null; coarsen(graph, nvtxs, nedges, using_vwgts, useEdgeWeights, dummy_twgt, igeom, coords, yvecs, ndims, solver_flag, vmax, eigtol, nstep, step, false); rqi_symmlq_time += seconds() - time; } else { /* Use standard Lanczos. */ if (PERTURB) { if (NPERTURB > 0 && PERTURB_MAX > 0.0) { perturb_init(nvtxs); if (DEBUG_PERTURB) { Trace.WriteLine($"Matrix being perturbed with scale {PERTURB_MAX:E}\n"); } } else if (DEBUG_PERTURB) { Trace.WriteLine("Matrix not being perturbed\n"); } } if (solver_flag == LanczosType.FullOrthogonalization) { time = seconds(); version = 1; lanczos_FO(graph, nvtxs, ndims, yvecs, evals, bound, eigtol, vwsqrt, maxdeg, version); lanczos_time += seconds() - time; } if (solver_flag == LanczosType.FullOrthogonalizationInverseOperator) { time = seconds(); version = 2; lanczos_FO(graph, nvtxs, ndims, yvecs, evals, bound, eigtol, vwsqrt, maxdeg, version); lanczos_time += seconds() - time; } else if (solver_flag == LanczosType.SelectiveOrthogonalization) { version = 2; /* orthog. against left end only */ if (LANCZOS_CONVERGENCE_MODE == 1) { active = (int *)Marshal.AllocHGlobal(nvtxs * sizeof(int)); } nsets = 1 << ndims; time = seconds(); if (LANCZOS_SO_PRECISION == 2) { /* double precision */ lanczos_SO(graph, nvtxs, ndims, yvecs, evals, bound, eigtol, vwsqrt, maxdeg, version, architecture, nsets, assignment, active, mediantype, goal, vwgt_max); } else { /* single precision */ lanczos_SO_float(graph, nvtxs, ndims, yvecs, evals, bound, eigtol, vwsqrt, maxdeg, version, architecture, nsets, assignment, active, mediantype, goal, vwgt_max); } lanczos_time += seconds() - time; } else if (solver_flag == LanczosType.SelectiveOrthogonalizationDoubleEnded) { if (EXPERT) { version = 1; /* orthog. against both ends */ } else { /* this should have been caught earlier ... */ version = 2; } if (LANCZOS_CONVERGENCE_MODE == 1) { active = (int *)Marshal.AllocHGlobal(nvtxs * sizeof(int)); } nsets = 1 << ndims; time = seconds(); if (LANCZOS_SO_PRECISION == 1) { /* Single precision */ lanczos_SO_float(graph, nvtxs, ndims, yvecs, evals, bound, eigtol, vwsqrt, maxdeg, version, architecture, nsets, assignment, active, mediantype, goal, vwgt_max); } else { /* Double precision */ lanczos_SO(graph, nvtxs, ndims, yvecs, evals, bound, eigtol, vwsqrt, maxdeg, version, architecture, nsets, assignment, active, mediantype, goal, vwgt_max); } lanczos_time += seconds() - time; } } /* * file = fopen("CHACO.EVECS", "w"); * for (i = 1; i <= nvtxs; i++) { * for (j = 1; j <= ndims; j++) { * fprintf(file, "%g ", (yvecs[j])[i]); * } * fprintf(file, "\n"); * } * fclose(file); */ if (PERTURB && NPERTURB > 0 && PERTURB_MAX > 0.0) { perturb_clear(); } } /* This is an attempt to reduce some machine-to-machine * variance. If the first value in the eigenvector is negative, * reflect the eigenvector... This may not be needed following * the addition of the standard random number generator in util/random.c */ for (nstep = 1; nstep <= ndims; nstep++) { vecnorm(yvecs[nstep], 1, nvtxs); } if (DEBUG_EVECS > 4) { for (nstep = 1; nstep <= ndims; nstep++) { vecout(yvecs[nstep], 1, nvtxs, "Eigenvector", null); } } /* Auto-reset (if necessary) some parameters for the eigen calculation */ if (autoset_maxitns) { LANCZOS_MAXITNS = prev_maxitns; } if (autoset_srestol) { SRESTOL = prev_srestol; } if (active != null) { Marshal.FreeHGlobal((IntPtr)active); } if (DEBUG_TRACE) { Trace.WriteLine("<Leaving eigensolve>\n"); } }
/* JPS END */ public static void sequence( vtx_data **graph, /* graph data structure */ int nvtxs, /* number of vertices in graph */ int nedges, /* number of edges in graph */ bool useEdgeWeights, /* are edge weights being used? */ double *sqrtVertexWeights, /* sqrt of vertex weights (length nvtxs+1) */ LanczosType solver_flag, /* which eigensolver should I use? */ bool rqi_flag, /* use multilevel eigensolver? */ int vmax, /* if so, how many vtxs to coarsen down to? */ double eigtol /* tolerance on eigenvectors */ ) { Trace.WriteLine($"<Entering {nameof(sequence)}>"); /* JPS * extern char SEQ_FILENAME[]; */ vtx_data **subgraph = null; /* subgraph data structure */ edgeslist *edgeslist; /* edges added for connectivity */ double *[] yvecs = new double *[MAXDIMS + 1]; /* space for pointing to eigenvectors */ double[] evals = new double[MAXDIMS + 1]; /* corresponding eigenvalues */ double[] goal = new double[2]; /* needed for eigen convergence mode = 1 */ float *[] terminalWeights = new float *[2]; /* dummy vector for terminal weights */ int * graphToSubgraphMap = null; /* maps graph vtxs to subgraph vtxs */ int * subtraphToGraphMap = null; /* maps subgraph vtxs to graph vtxs */ int * degree = null; /* degrees of vertices in subgraph */ var useVertexWeights = sqrtVertexWeights != null; /* are vertex weights being used? */ /* Sort each connected component seperately. */ // Stores the component number for each vertex. var vertexComponentMap = (int *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(int)); /* JPS * orderfile = fopen(SEQ_FILENAME, "w"); */ var space = (int *)Marshal.AllocHGlobal(nvtxs * sizeof(int)); var connectedComponentCount = find_edges(graph, nvtxs, vertexComponentMap, space, &edgeslist); ++connectedComponentCount; Trace.WriteLine("Found connected components: " + connectedComponentCount); free_edgeslist(edgeslist); yvecs[1] = (double *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(double)); terminalWeights[1] = null; double *subvwsqrt = null; /* vwsqrt vector for subgraphs */ if (RQI_CONVERGENCE_MODE != 0) { throw new InvalidOperationException(nameof(RQI_CONVERGENCE_MODE) + " should be 0 when using " + nameof(SEQUENCE) + " = true"); } if (LANCZOS_CONVERGENCE_MODE != 0) { throw new InvalidOperationException(nameof(LANCZOS_CONVERGENCE_MODE) + " should be 0 when using " + nameof(SEQUENCE) + " = true"); } var largestConnectedComponentSize = nvtxs; int *setsize = null; /* size of each connected component */ if (connectedComponentCount > 1) { /* Find size of largest set. */ setsize = (int *)Marshal.AllocHGlobal(connectedComponentCount * sizeof(int)); for (var comp = 0; comp < connectedComponentCount; comp++) { setsize[comp] = 0; } for (var i = 1; i <= nvtxs; i++) { ++setsize[vertexComponentMap[i]]; } largestConnectedComponentSize = 0; for (var comp = 0; comp < connectedComponentCount; comp++) { if (setsize[comp] > largestConnectedComponentSize) { largestConnectedComponentSize = setsize[comp]; } } graphToSubgraphMap = (int *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(int)); subtraphToGraphMap = (int *)Marshal.AllocHGlobal((largestConnectedComponentSize + 1) * sizeof(int)); subgraph = (vtx_data **)Marshal.AllocHGlobal((largestConnectedComponentSize + 1) * sizeof(vtx_data *)); degree = (int *)Marshal.AllocHGlobal((largestConnectedComponentSize + 1) * sizeof(int)); if (useVertexWeights) { subvwsqrt = (double *)Marshal.AllocHGlobal((largestConnectedComponentSize + 1) * sizeof(double)); } } var indices = (int *)Marshal.AllocHGlobal(largestConnectedComponentSize * sizeof(int)); for (var comp = 0; comp < connectedComponentCount; comp++) { int subgraphVertexCount; /* number of vertices in subgraph */ int subgraphEdgeCount; /* number of edges in subgraph */ if (connectedComponentCount > 1) { make_maps2(vertexComponentMap, nvtxs, comp, graphToSubgraphMap, subtraphToGraphMap); subgraphVertexCount = setsize[comp]; make_subgraph(graph, subgraph, subgraphVertexCount, &subgraphEdgeCount, vertexComponentMap, comp, graphToSubgraphMap, subtraphToGraphMap, degree, useEdgeWeights); if (useVertexWeights) { make_subvector(sqrtVertexWeights, subvwsqrt, subgraphVertexCount, subtraphToGraphMap); } } else { subgraph = graph; subgraphVertexCount = nvtxs; subgraphEdgeCount = nedges; subvwsqrt = sqrtVertexWeights; } var maxWeightedVertexDegree = find_maxdeg(subgraph, subgraphVertexCount, useEdgeWeights, (float *)null); Trace.WriteLine($"{nameof(maxWeightedVertexDegree)}: {maxWeightedVertexDegree}"); double totalVertexWeight; /* sum of all vertex weights */ int componentVertexWeightMax; /* largest vertex weight in component */ if (useVertexWeights) { componentVertexWeightMax = 0; totalVertexWeight = 0; for (var i = 1; i <= subgraphVertexCount; i++) { componentVertexWeightMax = Math.Max(subgraph[i]->vwgt, componentVertexWeightMax); totalVertexWeight += subgraph[i]->vwgt; } } else { componentVertexWeightMax = 1; totalVertexWeight = subgraphVertexCount; } goal[0] = goal[1] = totalVertexWeight / 2; Trace.WriteLine($"{nameof(useVertexWeights)}: {useVertexWeights}"); Trace.WriteLine($"{nameof(useEdgeWeights)}: {useEdgeWeights}"); if (subgraphVertexCount == 1) { yvecs[1][1] = 0; } else { eigensolve(subgraph, subgraphVertexCount, subgraphEdgeCount, maxWeightedVertexDegree, componentVertexWeightMax, subvwsqrt, useVertexWeights, useEdgeWeights, terminalWeights, 0, null, yvecs, evals, false, space, goal, solver_flag, rqi_flag, vmax, 1, MappingType.IndependantMedians, eigtol); } if (connectedComponentCount > 1) { remake_graph(subgraph, subgraphVertexCount, subtraphToGraphMap, degree, useEdgeWeights); } /* Sort values in eigenvector */ if (useVertexWeights) { y2x(yvecs, 1, subgraphVertexCount, subvwsqrt); } ch_mergesort(&(yvecs[1][1]), subgraphVertexCount, indices, space); /* Print out the order and the corresponding component of the eigenvector */ if (connectedComponentCount == 1) { for (var i = 0; i < subgraphVertexCount; i++) { /* JPS START */ jps_eigord[i] = indices[i] + 1; jps_eigvec[i] = (float)yvecs[1][indices[i] + 1]; /* JPS END */ /* JPS * fprintf(orderfile, "%-7d %9.6f\n", indices[i] + 1, yvecs[1][indices[i] + 1]); */ } } else { for (var i = 0; i < subgraphVertexCount; i++) { /* JPS START */ jps_eigord[i] = subtraphToGraphMap[indices[i] + 1]; jps_eigvec[i] = (float)yvecs[1][indices[i] + 1]; /* JPS END */ /* JPS * fprintf(orderfile, "%-7d %9.6f\n", loc2glob[indices[i] + 1], yvecs[1][indices[i] + 1]); */ } } } if (connectedComponentCount > 1) { Marshal.FreeHGlobal((IntPtr)degree); Marshal.FreeHGlobal((IntPtr)subgraph); Marshal.FreeHGlobal((IntPtr)subtraphToGraphMap); Marshal.FreeHGlobal((IntPtr)graphToSubgraphMap); Marshal.FreeHGlobal((IntPtr)setsize); if (useVertexWeights) { Marshal.FreeHGlobal((IntPtr)subvwsqrt); } } Marshal.FreeHGlobal((IntPtr)yvecs[1]); Marshal.FreeHGlobal((IntPtr)indices); Marshal.FreeHGlobal((IntPtr)space); Marshal.FreeHGlobal((IntPtr)vertexComponentMap); Trace.WriteLine($"{connectedComponentCount:D} connected components found."); }
public static void coarsen_kl( /* Coarsen until nvtxs < vmax, compute and uncoarsen. */ vtx_data **graph, /* array of vtx data for graph */ int nvtxs, /* number of vertices in graph */ int nedges, /* number of edges in graph */ bool using_vwgts, /* are vertices weights being used? */ bool useEdgeWeights, /* are edge weights being used? */ float *[] term_wgts, /* weights for terminal propagation */ int igeom, /* dimension for geometric information */ float **coords, /* coordinates for vertices */ int vwgt_max, /* largest vertex weight */ int *assignment, /* processor each vertex gets assigned to */ double[] goal, /* desired set sizes */ bool architecture, /* 0 => hypercube, d => d-dimensional mesh */ int[][] hops, /* cost of edge between sets */ LanczosType solver_flag, /* which eigensolver to use */ int ndims, /* number of eigenvectors to calculate */ int nsets, /* number of sets being divided into */ int vmax, /* largest subgraph to stop coarsening */ MappingType mediantype, /* flag for different assignment strategies */ bool mkconnected, /* make graph connected before eigensolver? */ double eigtol, /* tolerance in eigen calculation */ int nstep, /* number of coarsenings between RQI steps */ int step, /* current step number */ int **pbndy_list, /* pointer to returned boundary list */ double[] weights, /* weights of vertices in each set */ bool give_up /* has coarsening bogged down? */ ) { connect_data *cdata; /* data structure for enforcing connectivity */ vtx_data ** cgraph; /* array of vtx data for coarsened graph */ double *[] yvecs = new double *[MAXDIMS + 1]; /* eigenvectors for subgraph */ double[] evals = new double[MAXDIMS + 1]; /* eigenvalues returned */ double[] new_goal = new double[MAXSETS]; /* new goal if not using vertex weights */ double[] real_goal; /* chooses between goal and new_goal */ double goal_weight; /* total weight of vertices in goal */ double * vwsqrt = null; /* square root of vertex weights */ double maxdeg; /* maximum weighted degree of a vertex */ double[] temp_goal = new double[2]; /* goal to simulate bisection while striping */ double[] fake_goal; /* either goal or temp_goal */ float *[] cterm_wgts = new float *[MAXSETS]; /* terminal weights for coarse graph */ float *[] new_term_wgts = new float *[MAXSETS]; /* modified for Bui's method */ float *[] real_term_wgts; /* which of previous two to use */ float ewgt_max; /* largest edge weight in graph */ float * twptr; /* loops through term_wgts */ float * twptr_save; /* copy of twptr */ float * ctwptr; /* loops through cterm_wgts */ float ** ccoords; /* coarse graph coordinates */ int * active; /* space for assign routine */ int * v2cv; /* mapping from fine to coarse vertices */ int * cv2v; /* mapping from coarse to fine vertices */ int * bndy_list; /* list of vertices on boundary */ int * cbndy_list; /* list of vertices of coarse graph on boundary */ int * mflag; /* flags indicating matching */ int * cassignment; /* set assignments for coarsened vertices */ int clist_length; /* length of coarse graph boundary vtx list */ int list_length; /* length of boundary vtx list */ int vtx; /* vertex in graph */ int cvtx; /* vertex in coarse graph */ int cnvtxs; /* number of vertices in coarsened graph */ int cnedges; /* number of edges in coarsened graph */ int cvwgt_max; /* largest vertex weight in coarsened graph */ int nextstep; /* next step in RQI test */ int max_dev; /* largest allowed deviation from balance */ int set; /* set a vertex is in */ int i, j; /* loop counters */ if (DEBUG_COARSEN || DEBUG_TRACE) { Trace.WriteLine($"<Entering coarsen_kl, {nameof(step)}={step:d}, {nameof(nvtxs)}={nvtxs:d}, {nameof(nedges)}={nedges:d}, {nameof(vmax)}={vmax:d}>"); } /* Is problem small enough to solve? */ if (nvtxs <= vmax || give_up) { if (using_vwgts) { vwsqrt = (double *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(double)); makevwsqrt(vwsqrt, graph, nvtxs); } else { vwsqrt = null; } /* Create space for subgraph yvecs. */ for (i = 1; i <= ndims; i++) { yvecs[i] = (double *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(double)); } active = (int *)Marshal.AllocHGlobal(nvtxs * sizeof(int)); if (mkconnected) { make_connected(graph, nvtxs, &nedges, (int *)&(yvecs[1][0]), active, &cdata, useEdgeWeights); if (DEBUG_CONNECTED) { Trace.WriteLine("Enforcing connectivity on coarse graph"); print_connected(cdata); } } /* If not coarsening ewgts, then need care with term_wgts. */ if (!useEdgeWeights && term_wgts[1] != null && step != 0) { twptr = (float *)Marshal.AllocHGlobal((nvtxs + 1) * (nsets - 1) * sizeof(float)); twptr_save = twptr; for (j = 1; j < nsets; j++) { new_term_wgts[j] = twptr; twptr += nvtxs + 1; } for (j = 1; j < nsets; j++) { twptr = term_wgts[j]; ctwptr = new_term_wgts[j]; for (i = 1; i <= nvtxs; i++) { if (twptr[i] > .5) { ctwptr[i] = 1; } else if (twptr[i] < -.5) { ctwptr[i] = -1; } else { ctwptr[i] = 0; } } } real_term_wgts = new_term_wgts; } else { real_term_wgts = term_wgts; new_term_wgts[1] = null; } if (!COARSEN_VWGTS && step != 0) { /* Construct new goal */ goal_weight = 0; for (i = 0; i < nsets; i++) { goal_weight += goal[i]; } for (i = 0; i < nsets; i++) { new_goal[i] = goal[i] * (nvtxs / goal_weight); } real_goal = new_goal; } else { real_goal = goal; } if (ndims == 1 && nsets > 2) { /* Striping. */ mediantype = MappingType.Striped; temp_goal[0] = temp_goal[1] = 0; for (i = 0; 2 * i + 1 < nsets; i++) { temp_goal[0] += real_goal[i]; temp_goal[1] += real_goal[nsets - 1 - i]; } i = nsets / 2; if (2 * i != nsets) { temp_goal[0] += .5 * real_goal[i]; temp_goal[1] += .5 * real_goal[i]; } fake_goal = temp_goal; } else { mediantype = MAPPING_TYPE; fake_goal = real_goal; } /* Partition coarse graph with spectral method */ maxdeg = find_maxdeg(graph, nvtxs, useEdgeWeights, &ewgt_max); eigensolve(graph, nvtxs, nedges, maxdeg, vwgt_max, vwsqrt, using_vwgts, useEdgeWeights, real_term_wgts, 0, (float **)null, yvecs, evals, architecture, assignment, fake_goal, solver_flag, false, 0, ndims, mediantype, eigtol); if (mkconnected) { make_unconnected(graph, &nedges, &cdata, useEdgeWeights); } Assign(graph, yvecs, nvtxs, ndims, architecture, nsets, vwsqrt, assignment, active, mediantype, real_goal, vwgt_max); /* * simple_part(graph, nvtxs, assignment, nsets, 1, real_goal); */ Marshal.FreeHGlobal((IntPtr)active); count_weights(graph, nvtxs, assignment, nsets, weights, (vwgt_max != 1)); bndy_list = null; if (COARSE_KL_BOTTOM || (step % nstep) == 0) { if (LIMIT_KL_EWGTS) { compress_ewgts(graph, nvtxs, nedges, ewgt_max, useEdgeWeights); } max_dev = (step == 0) ? vwgt_max : 5 * vwgt_max; goal_weight = 0; for (i = 0; i < nsets; i++) { goal_weight += real_goal[i]; } goal_weight *= KL_IMBALANCE / nsets; if (goal_weight > max_dev) { max_dev = (int)goal_weight; } if (KL_ONLY_BNDY) { /* On small graph, quickest to include everybody in list. */ bndy_list = (int *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(int)); for (i = 0; i < nvtxs; i++) { bndy_list[i] = i + 1; } bndy_list[nvtxs] = 0; } klspiff(graph, nvtxs, assignment, nsets, hops, real_goal, real_term_wgts, max_dev, maxdeg, useEdgeWeights, &bndy_list, weights); if (LIMIT_KL_EWGTS) { restore_ewgts(graph, nvtxs); } } else if (KL_ONLY_BNDY) { /* Find boundary vertices directly. */ bndy_list = (int *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(int)); list_length = 0; for (i = 1; i <= nvtxs; i++) { set = assignment[i]; for (j = 1; j < graph[i]->nedges; j++) { if (assignment[graph[i]->edges[j]] != set) { bndy_list[list_length++] = i; break; } } } bndy_list[list_length] = 0; bndy_list = (int *)Marshal.ReAllocHGlobal((IntPtr)bndy_list, new IntPtr((list_length + 1) * sizeof(int))); } *pbndy_list = bndy_list; if (real_term_wgts != term_wgts && new_term_wgts[1] != null) { Marshal.FreeHGlobal((IntPtr)real_term_wgts[1]); } if (vwsqrt != null) { Marshal.FreeHGlobal((IntPtr)vwsqrt); } for (i = ndims; i > 0; i--) { Marshal.FreeHGlobal((IntPtr)yvecs[i]); } return; } /* Otherwise I have to coarsen. */ if (coords != null) { ccoords = (float **)Marshal.AllocHGlobal(igeom * sizeof(float *)); } else { ccoords = null; } coarsen1(graph, nvtxs, nedges, &cgraph, &cnvtxs, &cnedges, &v2cv, igeom, coords, ccoords, useEdgeWeights); if (term_wgts[1] != null) { twptr = (float *)Marshal.AllocHGlobal((cnvtxs + 1) * (nsets - 1) * sizeof(float)); twptr_save = twptr; for (i = (cnvtxs + 1) * (nsets - 1); i != 0; i--) { *twptr++ = 0; } twptr = twptr_save; for (j = 1; j < nsets; j++) { cterm_wgts[j] = twptr; twptr += cnvtxs + 1; } for (j = 1; j < nsets; j++) { ctwptr = cterm_wgts[j]; twptr = term_wgts[j]; for (i = 1; i < nvtxs; i++) { ctwptr[v2cv[i]] += twptr[i]; } } } else { cterm_wgts[1] = null; } /* If coarsening isn't working very well, give up and partition. */ give_up = false; if (nvtxs * COARSEN_RATIO_MIN < cnvtxs && cnvtxs > vmax) { Trace.WriteLine($"WARNING: Coarsening not making enough progress, {nameof(nvtxs)} = {nvtxs:d}, {nameof(cnvtxs)} = {cnvtxs:d}."); Trace.WriteLine(" Recursive coarsening being stopped prematurely."); give_up = true; } /* Now recurse on coarse subgraph. */ if (COARSEN_VWGTS) { cvwgt_max = 0; for (i = 1; i <= cnvtxs; i++) { if (cgraph[i]->vwgt > cvwgt_max) { cvwgt_max = cgraph[i]->vwgt; } } } else { cvwgt_max = 1; } cassignment = (int *)Marshal.AllocHGlobal((cnvtxs + 1) * sizeof(int)); nextstep = step + 1; coarsen_kl(cgraph, cnvtxs, cnedges, COARSEN_VWGTS, COARSEN_EWGTS, cterm_wgts, igeom, ccoords, cvwgt_max, cassignment, goal, architecture, hops, solver_flag, ndims, nsets, vmax, mediantype, mkconnected, eigtol, nstep, nextstep, &cbndy_list, weights, give_up); /* Interpolate assignment back to fine graph. */ for (i = 1; i <= nvtxs; i++) { assignment[i] = cassignment[v2cv[i]]; } if (KL_ONLY_BNDY) { /* Construct boundary list from coarse boundary list. */ cv2v = (int *)Marshal.AllocHGlobal((cnvtxs + 1) * sizeof(int)); mflag = (int *)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(int)); for (i = 1; i <= cnvtxs; i++) { cv2v[i] = 0; } for (i = 1; i <= nvtxs; i++) { mflag[i] = 0; cvtx = v2cv[i]; if (cv2v[cvtx] == 0) { cv2v[cvtx] = i; } else { mflag[cv2v[cvtx]] = i; } } clist_length = 0; while (cbndy_list[clist_length] != 0) { clist_length++; } bndy_list = (int *)Marshal.AllocHGlobal((2 * clist_length + 1) * sizeof(int)); list_length = 0; for (i = 0; i < clist_length; i++) { vtx = cv2v[cbndy_list[i]]; bndy_list[list_length++] = vtx; if (mflag[vtx] != 0) { bndy_list[list_length++] = mflag[vtx]; } } bndy_list[list_length] = 0; bndy_list = (int *)Marshal.ReAllocHGlobal((IntPtr)bndy_list, new IntPtr((list_length + 1) * sizeof(int))); Marshal.FreeHGlobal((IntPtr)mflag); Marshal.FreeHGlobal((IntPtr)cv2v); Marshal.FreeHGlobal((IntPtr)cbndy_list); } else { bndy_list = null; } /* Free the space that was allocated. */ Marshal.FreeHGlobal((IntPtr)cassignment); if (cterm_wgts[1] != null) { Marshal.FreeHGlobal((IntPtr)cterm_wgts[1]); } free_graph(cgraph); Marshal.FreeHGlobal((IntPtr)v2cv); /* Smooth using KL every nstep steps. */ if ((step % nstep) == 0) { if (!COARSEN_VWGTS && step != 0) { /* Construct new goal */ goal_weight = 0; for (i = 0; i < nsets; i++) { goal_weight += goal[i]; } for (i = 0; i < nsets; i++) { new_goal[i] = goal[i] * (nvtxs / goal_weight); } real_goal = new_goal; } else { real_goal = goal; } maxdeg = find_maxdeg(graph, nvtxs, useEdgeWeights, &ewgt_max); if (LIMIT_KL_EWGTS) { compress_ewgts(graph, nvtxs, nedges, ewgt_max, useEdgeWeights); } /* If not coarsening ewgts, then need care with term_wgts. */ if (!useEdgeWeights && term_wgts[1] != null && step != 0) { twptr = (float *)Marshal.AllocHGlobal((nvtxs + 1) * (nsets - 1) * sizeof(float)); twptr_save = twptr; for (j = 1; j < nsets; j++) { new_term_wgts[j] = twptr; twptr += nvtxs + 1; } for (j = 1; j < nsets; j++) { twptr = term_wgts[j]; ctwptr = new_term_wgts[j]; for (i = 1; i <= nvtxs; i++) { if (twptr[i] > .5) { ctwptr[i] = 1; } else if (twptr[i] < -.5) { ctwptr[i] = -1; } else { ctwptr[i] = 0; } } } real_term_wgts = new_term_wgts; } else { real_term_wgts = term_wgts; new_term_wgts[1] = null; } max_dev = (step == 0) ? vwgt_max : 5 * vwgt_max; goal_weight = 0; for (i = 0; i < nsets; i++) { goal_weight += real_goal[i]; } goal_weight *= KL_IMBALANCE / nsets; if (goal_weight > max_dev) { max_dev = (int)goal_weight; } if (!COARSEN_VWGTS) { count_weights(graph, nvtxs, assignment, nsets, weights, (vwgt_max != 1)); } klspiff(graph, nvtxs, assignment, nsets, hops, real_goal, real_term_wgts, max_dev, maxdeg, useEdgeWeights, &bndy_list, weights); if (real_term_wgts != term_wgts && new_term_wgts[1] != null) { Marshal.FreeHGlobal((IntPtr)real_term_wgts[1]); } if (LIMIT_KL_EWGTS) { restore_ewgts(graph, nvtxs); } } *pbndy_list = bndy_list; if (ccoords != null) { for (i = 0; i < igeom; i++) { Marshal.FreeHGlobal((IntPtr)ccoords[i]); } Marshal.FreeHGlobal((IntPtr)ccoords); } if (DEBUG_COARSEN) { Trace.WriteLine($" Leaving coarsen_kl, {nameof(step)}={step:d}"); } }