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); }
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); }
/* 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); }
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); }
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]]++; } } }
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); }
/* 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; }
/// <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); }
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); }
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; } } }
/// <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); }
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; }
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++; } } } } }
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}"); }
/// <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]); }
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})"); } } } } }
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; } }
/// <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); }
/* 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); }
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; } } } }
/// <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); }
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); } } }
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; } }
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; }
/// <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; } } }
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); }
/// <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); }
/// <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); } }
/* 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; }
/* 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"); } }