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 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); }
/* Change from a FORTRAN graph style to our graph data structure. */ public static bool reformat(int *start, /* start of edge list for each vertex */ int *adjacency, /* edge list data */ int nvtxs, /* number of vertices in graph */ int *pnedges, /* ptr to number of edges in graph */ int *vwgts, /* weights for all vertices */ float *ewgts, /* weights for all edges */ vtx_data ***pgraph /* ptr to array of vtx data for graph */ ) { Trace.WriteLine($"<Entering {nameof(reformat)}>"); vtx_data **graph = null; /* array of vtx data for graph */ vtx_data * links = null; /* space for data for all vtxs */ int * edges = null; /* space for all adjacency lists */ float * eweights = null; /* space for all edge weights */ int * eptr = null; /* steps through adjacency list */ int * eptr_save = null; /* saved index into adjacency list */ float * wptr = null; /* steps through edge weights list */ int self_edge; /* number of self loops detected */ int size; /* length of all edge lists */ double sum; /* sum of edge weights for a vtx */ int i, j; /* loop counters */ var useEdgeWeights = (ewgts != null); /* are edge weights being used? */ var using_vwgts = (vwgts != null); /* are vertex weights being used? */ graph = (vtx_data **)Marshal.AllocHGlobal((nvtxs + 1) * sizeof(vtx_data *)); *pgraph = graph; if (graph == null) { return(true); } graph[1] = null; /* Set up all the basic data structure for the vertices. */ /* Replace many small mallocs by a few large ones. */ links = (vtx_data *)Marshal.AllocHGlobal((nvtxs) * sizeof(vtx_data)); if (links == null) { return(true); } for (i = 1; i <= nvtxs; i++) { graph[i] = links++; } graph[1]->edges = null; graph[1]->ewgts = null; /* Now fill in all the data fields. */ if (start != null) { *pnedges = start[nvtxs] / 2; } else { *pnedges = 0; } size = 2 * (*pnedges) + nvtxs; edges = (int *)Marshal.AllocHGlobal(size * sizeof(int)); if (edges == null) { return(true); } if (useEdgeWeights) { eweights = (float *)Marshal.AllocHGlobal(size * sizeof(float)); if (eweights == null) { return(true); } } if (start != null) { eptr = adjacency + start[0]; wptr = ewgts; } self_edge = 0; for (i = 1; i <= nvtxs; i++) { if (using_vwgts) { graph[i]->vwgt = *(vwgts++); } else { graph[i]->vwgt = 1; } if (start != null) { size = start[i] - start[i - 1]; } else { size = 0; } graph[i]->nedges = size + 1; graph[i]->edges = edges; *edges++ = i; eptr_save = eptr; for (j = size; j != 0; j--) { if (*eptr != i) { *edges++ = *eptr++; } else { /* Self edge, skip it. */ //if (self_edge == 0) { Trace.WriteLine($"WARNING: Self edge ({i:d},{i:d}) being ignored"); } ++self_edge; eptr++; --(graph[i]->nedges); --(*pnedges); } } if (useEdgeWeights) { graph[i]->ewgts = eweights; eweights++; sum = 0; for (j = size; j != 0; j--) { if (*eptr_save++ != i) { sum += *wptr; *eweights++ = *wptr++; } else { wptr++; } } graph[i]->ewgts[0] = (float)-sum; } else { graph[i]->ewgts = null; } } if (self_edge > 1) { Trace.WriteLine($"WARNING: {self_edge:d} self edges were detected and ignored"); } return(false); }
/* Construct a weighted quotient graph representing the inter-set communication. */ public static bool make_comm_graph(vtx_data ***pcomm_graph, /* graph for communication requirements */ vtx_data **graph, /* graph data structure */ int nvtxs, /* number of vertices in graph */ bool useEdgeWeights, /* are edge weights being used? */ int *assign, /* current assignment */ int nsets_tot /* total number of sets */ ) { float ewgt; /* edge weight in graph */ int ** edges_list = null; /* lists of edges */ int ** ewgts_list = null; /* lists of edge weights */ int * edges = null; /* edges in communication graph */ int * ewgts = null; /* edge weights in communication graph */ float *float_ewgts = null; /* edge weights in floating point */ int * adj_sets = null; /* weights connecting sets */ int * order = null; /* ordering of vertices by set */ int * sizes = null; /* sizes of different sets */ int * start = null; /* pointers into adjacency data */ int * adjacency = null; /* array with all the edge info */ int * eptr = null; /* loops through edges in graph */ int * ewptr = null; /* loop through edge weights */ int set, set2; /* sets two vertices belong to */ int vertex; /* vertex in graph */ int ncomm_edges; /* number of edges in communication graph */ bool error; /* out of space? */ int i, j; /* loop counters */ error = true; *pcomm_graph = null; /* First construct some mappings to ease later manipulations. */ sizes = (int *)Marshal.AllocHGlobal(nsets_tot * sizeof(int)); if (sizes == null) { goto skip; } for (i = 0; i < nsets_tot; i++) { sizes[i] = 0; } for (i = 1; i <= nvtxs; i++) { ++(sizes[assign[i]]); } /* Now make sizes reflect the start index for each set. */ for (i = 1; i < nsets_tot - 1; i++) { sizes[i] += sizes[i - 1]; } for (i = nsets_tot - 1; i != 0; i--) { sizes[i] = sizes[i - 1]; } sizes[0] = 0; /* Now construct list of all vertices in set 0, all in set 1, etc. */ order = (int *)Marshal.AllocHGlobal(nvtxs * sizeof(int)); if (order == null) { goto skip; } for (i = 1; i <= nvtxs; i++) { set = assign[i]; order[sizes[set]] = i; ++sizes[set]; } /* For each set, find total weight to all neighbors. */ adj_sets = (int *)Marshal.AllocHGlobal(nsets_tot * sizeof(int)); edges_list = (int **)Marshal.AllocHGlobal(nsets_tot * sizeof(int *)); ewgts_list = (int **)Marshal.AllocHGlobal(nsets_tot * sizeof(int *)); start = (int *)Marshal.AllocHGlobal((nsets_tot + 1) * sizeof(int)); if (adj_sets == null || edges_list == null || ewgts_list == null || start == null) { goto skip; } start[0] = 0; ewgt = 1; ncomm_edges = 0; for (set = 0; set < nsets_tot; set++) { edges_list[set] = null; ewgts_list[set] = null; } for (set = 0; set < nsets_tot; set++) { for (i = 0; i < nsets_tot; i++) { adj_sets[i] = 0; } for (i = (set != 0 ? sizes[set - 1] : 0); i < sizes[set]; i++) { vertex = order[i]; for (j = 1; j < graph[vertex]->nedges; j++) { set2 = assign[graph[vertex]->edges[j]]; if (set2 != set) { if (useEdgeWeights) { ewgt = graph[vertex]->ewgts[j]; } adj_sets[set2] += (int)ewgt; } } } /* Now save adj_sets data to later construct graph. */ j = 0; for (i = 0; i < nsets_tot; i++) { if (adj_sets[i] != 0) { j++; } } ncomm_edges += j; start[set + 1] = ncomm_edges; if (j != 0) { edges_list[set] = edges = (int *)Marshal.AllocHGlobal(j * sizeof(int)); ewgts_list[set] = ewgts = (int *)Marshal.AllocHGlobal(j * sizeof(int)); if (edges == null || ewgts == null) { goto skip; } } j = 0; for (i = 0; i < nsets_tot; i++) { if (adj_sets[i] != 0) { edges[j] = i + 1; ewgts[j] = adj_sets[i]; j++; } } } Marshal.FreeHGlobal((IntPtr)adj_sets); Marshal.FreeHGlobal((IntPtr)order); Marshal.FreeHGlobal((IntPtr)sizes); adj_sets = order = sizes = null; /* I now need to pack the edge and weight data into single arrays. */ adjacency = (int *)Marshal.AllocHGlobal((ncomm_edges + 1) * sizeof(int)); float_ewgts = (float *)Marshal.AllocHGlobal((ncomm_edges + 1) * sizeof(float)); if (adjacency == null || float_ewgts == null) { goto skip; } for (set = 0; set < nsets_tot; set++) { j = start[set]; eptr = edges_list[set]; ewptr = ewgts_list[set]; for (i = start[set]; i < start[set + 1]; i++) { adjacency[i] = eptr[i - j]; float_ewgts[i] = ewptr[i - j]; } if (start[set] != start[set + 1]) { Marshal.FreeHGlobal((IntPtr)edges_list[set]); Marshal.FreeHGlobal((IntPtr)ewgts_list[set]); } } Marshal.FreeHGlobal((IntPtr)edges_list); Marshal.FreeHGlobal((IntPtr)ewgts_list); edges_list = ewgts_list = null; error = reformat(start, adjacency, nsets_tot, &ncomm_edges, (int *)null, float_ewgts, pcomm_graph); skip: Marshal.FreeHGlobal((IntPtr)adj_sets); Marshal.FreeHGlobal((IntPtr)order); Marshal.FreeHGlobal((IntPtr)sizes); if (edges_list != null) { for (set = nsets_tot - 1; set >= 0; set--) { if (edges_list[set] != null) { Marshal.FreeHGlobal((IntPtr)edges_list[set]); } } Marshal.FreeHGlobal((IntPtr)edges_list); } if (ewgts_list != null) { for (set = nsets_tot - 1; set >= 0; set--) { if (ewgts_list[set] != null) { Marshal.FreeHGlobal((IntPtr)ewgts_list[set]); } } Marshal.FreeHGlobal((IntPtr)ewgts_list); } Marshal.FreeHGlobal((IntPtr)float_ewgts); Marshal.FreeHGlobal((IntPtr)adjacency); Marshal.FreeHGlobal((IntPtr)start); return(error); }
public static void makefgraph(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 cnvtxs, /* number of vtxs in coarsened graph */ int *pcnedges, /* number of edges in coarsened graph */ int *v2cv, /* mapping from vtxs to coarsened vtxs */ bool useEdgeWeights, /* are edge weights being used? */ int igeom, /* dimensions of geometric data */ float **coords, /* coordinates for vertices */ float **ccoords /* coordinates for coarsened vertices */ ) { vtx_data **cgraph = null; /* coarsened version of graph */ vtx_data * links = null; /* space for all the vertex data */ vtx_data **gptr = null; /* loops through cgraph */ vtx_data * cgptr = null; /* loops through cgraph */ int * iptr = null; /* loops through integer arrays */ int * seenflag = null; /* flags for vtxs already put in edge list */ int * sptr = null; /* loops through seenflags */ int * cv2v_vals = null; /* vtxs corresponding to each cvtx */ int * cv2v_ptrs = null; /* indices into cv2v_vals */ float * eweights = null; /* space for edge weights in coarsened graph */ float * ewptr = null; /* loops through eweights */ float * fptr = null; /* loops through eweights */ float ewgt; /* edge weight */ double ewgt_sum; /* sum of edge weights */ double time; /* timing parameters */ int nseen; /* number of edges of coarse graph seen so far */ int vtx; /* vertex in original graph */ int cvtx; /* vertex in coarse graph */ int cnedges; /* twice number of edges in coarsened graph */ int neighbor; /* neighboring vertex */ int size; /* space needed for coarsened graph */ int * edges = null; /* space for edges in coarsened graph */ int * eptr = null; /* loops through edges data structure */ int cneighbor; /* neighboring vertex number in coarsened graph */ int i, j; /* loop counters */ /* Compute the number of vertices and edges in the coarsened graph, */ /* and construct start pointers into coarsened edge array. */ time = seconds(); /* Construct mapping from original graph vtxs to coarsened graph vtxs. */ cv2v_vals = (int *)Marshal.AllocHGlobal(nvtxs * sizeof(int)); cv2v_ptrs = (int *)Marshal.AllocHGlobal((cnvtxs + 2) * sizeof(int)); makecv2v(nvtxs, cnvtxs, v2cv, cv2v_vals, cv2v_ptrs); /* Compute an upper bound on the number of coarse graph edges. */ cnedges = nedges - (nvtxs - cnvtxs); /* Now allocate space for the new graph. Overallocate and realloc later. */ *pcgraph = cgraph = (vtx_data **)Marshal.AllocHGlobal((cnvtxs + 1) * sizeof(vtx_data *)); links = (vtx_data *)Marshal.AllocHGlobal(cnvtxs * sizeof(vtx_data)); size = 2 * cnedges + cnvtxs; edges = (int *)Marshal.AllocHGlobal(size * sizeof(int)); if (COARSEN_EWGTS) { ewptr = eweights = (float *)Marshal.AllocHGlobal(size * sizeof(float)); } /* Zero all the seen flags. */ seenflag = (int *)Marshal.AllocHGlobal((cnvtxs + 1) * sizeof(int)); sptr = seenflag; for (i = cnvtxs; i != 0; i--) { *(++sptr) = 0; } /* Use the renumbering to fill in the edge lists for the new graph. */ cnedges = 0; eptr = edges; ewgt = 1; sptr = cv2v_vals; for (cvtx = 1; cvtx <= cnvtxs; cvtx++) { nseen = 1; cgptr = cgraph[cvtx] = links++; if (COARSEN_VWGTS) { cgptr->vwgt = 0; } else { cgptr->vwgt = 1; } eptr[0] = cvtx; cgptr->edges = eptr; if (COARSEN_EWGTS) { cgptr->ewgts = ewptr; } else { cgptr->ewgts = null; } ewgt_sum = 0; for (i = cv2v_ptrs[cvtx + 1] - cv2v_ptrs[cvtx]; i != 0; i--) { vtx = *sptr++; iptr = graph[vtx]->edges; if (useEdgeWeights) { fptr = graph[vtx]->ewgts; } for (j = graph[vtx]->nedges - 1; j != 0; j--) { neighbor = *(++iptr); cneighbor = v2cv[neighbor]; if (cneighbor != cvtx) { if (useEdgeWeights) { ewgt = *(++fptr); } ewgt_sum += ewgt; /* Seenflags being used as map from cvtx to index. */ if (seenflag[cneighbor] == 0) { /* New neighbor. */ cgptr->edges[nseen] = cneighbor; if (COARSEN_EWGTS) { cgptr->ewgts[nseen] = ewgt; } seenflag[cneighbor] = nseen++; } else { /* Already seen neighbor. */ if (COARSEN_EWGTS) { cgptr->ewgts[seenflag[cneighbor]] += ewgt; } } } else if (useEdgeWeights) { ++fptr; } } } /* Now clear the seenflag values. */ iptr = cgptr->edges; for (j = nseen - 1; j != 0; j--) { seenflag[*(++iptr)] = 0; } if (COARSEN_EWGTS) { cgptr->ewgts[0] = (float)-ewgt_sum; } /* Increment pointers into edges list. */ cgptr->nedges = nseen; eptr += nseen; if (COARSEN_EWGTS) { ewptr += nseen; } cnedges += nseen - 1; } Marshal.FreeHGlobal((IntPtr)seenflag); /* Form new vertex weights by adding those from contracted edges. */ if (COARSEN_VWGTS) { gptr = graph; for (i = 1; i <= nvtxs; i++) { cgraph[v2cv[i]]->vwgt += (*(++gptr))->vwgt; } } /* Reduce arrays to actual sizes */ cnedges /= 2; size = 2 * cnedges + cnvtxs; eptr = edges; edges = (int *)Marshal.ReAllocHGlobal((IntPtr)edges, (IntPtr)(size * sizeof(int))); if (eptr != edges) { /* Need to reset pointers in graph. */ for (i = 1; i <= cnvtxs; i++) { cgraph[i]->edges = edges; edges += cgraph[i]->nedges; } } if (COARSEN_EWGTS) { ewptr = eweights; eweights = (float *)Marshal.ReAllocHGlobal((IntPtr)eweights, (IntPtr)(size * sizeof(float))); if (ewptr != eweights) { /* Need to reset pointers in graph. */ for (i = 1; i <= cnvtxs; i++) { cgraph[i]->ewgts = eweights; eweights += cgraph[i]->nedges; } } } /* If desired, make new vtx coordinates = center-of-mass of their parents. */ if (coords != null && ccoords != null && igeom > 0) { makeccoords(graph, cnvtxs, cv2v_ptrs, cv2v_vals, igeom, coords, ccoords); } *pcnedges = cnedges; Marshal.FreeHGlobal((IntPtr)cv2v_ptrs); Marshal.FreeHGlobal((IntPtr)cv2v_vals); if (DEBUG_COARSEN) { Trace.WriteLine($" Coarse graph has {cnvtxs:D} vertices and {cnedges:D} edges"); } make_cgraph_time += seconds() - time; }