Path: blob/devel/elmergrid/src/metis-5.1.0/GKlib/graph.c
3206 views
/*!1* \file2*3* \brief Various routines with dealing with sparse graphs4*5* \author George Karypis6* \version\verbatim $Id: graph.c 13328 2012-12-31 14:57:40Z karypis $ \endverbatim7*/89#include <GKlib.h>1011#define OMPMINOPS 500001213/*************************************************************************/14/*! Allocate memory for a graph and initializes it15\returns the allocated graph. The various fields are set to NULL.16*/17/**************************************************************************/18gk_graph_t *gk_graph_Create()19{20gk_graph_t *graph;2122graph = (gk_graph_t *)gk_malloc(sizeof(gk_graph_t), "gk_graph_Create: graph");2324gk_graph_Init(graph);2526return graph;27}282930/*************************************************************************/31/*! Initializes the graph.32\param graph is the graph to be initialized.33*/34/*************************************************************************/35void gk_graph_Init(gk_graph_t *graph)36{37memset(graph, 0, sizeof(gk_graph_t));38graph->nvtxs = -1;39}404142/*************************************************************************/43/*! Frees all the memory allocated for a graph.44\param graph is the graph to be freed.45*/46/*************************************************************************/47void gk_graph_Free(gk_graph_t **graph)48{49if (*graph == NULL)50return;51gk_graph_FreeContents(*graph);52gk_free((void **)graph, LTERM);53}545556/*************************************************************************/57/*! Frees only the memory allocated for the graph's different fields and58sets them to NULL.59\param graph is the graph whose contents will be freed.60*/61/*************************************************************************/62void gk_graph_FreeContents(gk_graph_t *graph)63{64gk_free((void *)&graph->xadj, &graph->adjncy,65&graph->iadjwgt, &graph->fadjwgt,66&graph->ivwgts, &graph->fvwgts,67&graph->ivsizes, &graph->fvsizes,68&graph->vlabels,69LTERM);70}717273/**************************************************************************/74/*! Reads a sparse graph from the supplied file75\param filename is the file that stores the data.76\param format is the graph format. The supported values are:77GK_GRAPH_FMT_METIS.78\param isfewgts is 1 if the edge-weights should be read as floats79\param isfvwgts is 1 if the vertex-weights should be read as floats80\param isfvsizes is 1 if the vertex-sizes should be read as floats81\returns the graph that was read.82*/83/**************************************************************************/84gk_graph_t *gk_graph_Read(char *filename, int format, int isfewgts,85int isfvwgts, int isfvsizes)86{87ssize_t i, k, l;88size_t nfields, nvtxs, nedges, fmt, ncon, lnlen;89int32_t ival;90float fval;91int readsizes=0, readwgts=0, readvals=0, numbering=0;92char *line=NULL, *head, *tail, fmtstr[256];93FILE *fpin=NULL;94gk_graph_t *graph=NULL;959697if (!gk_fexists(filename))98gk_errexit(SIGERR, "File %s does not exist!\n", filename);99100if (format == GK_GRAPH_FMT_METIS) {101fpin = gk_fopen(filename, "r", "gk_graph_Read: fpin");102do {103if (gk_getline(&line, &lnlen, fpin) <= 0)104gk_errexit(SIGERR, "Premature end of input file: file:%s\n", filename);105} while (line[0] == '%');106107fmt = ncon = 0;108nfields = sscanf(line, "%zu %zu %zu %zu", &nvtxs, &nedges, &fmt, &ncon);109if (nfields < 2)110gk_errexit(SIGERR, "Header line must contain at least 2 integers (#vtxs and #edges).\n");111112nedges *= 2;113114if (fmt > 111)115gk_errexit(SIGERR, "Cannot read this type of file format [fmt=%zu]!\n", fmt);116117sprintf(fmtstr, "%03zu", fmt%1000);118readsizes = (fmtstr[0] == '1');119readwgts = (fmtstr[1] == '1');120readvals = (fmtstr[2] == '1');121numbering = 1;122ncon = (ncon == 0 ? 1 : ncon);123}124else {125gk_errexit(SIGERR, "Unrecognized format: %d\n", format);126}127128graph = gk_graph_Create();129130graph->nvtxs = nvtxs;131132graph->xadj = gk_zmalloc(nvtxs+1, "gk_graph_Read: xadj");133graph->adjncy = gk_i32malloc(nedges, "gk_graph_Read: adjncy");134if (readvals) {135if (isfewgts)136graph->fadjwgt = gk_fmalloc(nedges, "gk_graph_Read: fadjwgt");137else138graph->iadjwgt = gk_i32malloc(nedges, "gk_graph_Read: iadjwgt");139}140141if (readsizes) {142if (isfvsizes)143graph->fvsizes = gk_fmalloc(nvtxs, "gk_graph_Read: fvsizes");144else145graph->ivsizes = gk_i32malloc(nvtxs, "gk_graph_Read: ivsizes");146}147148if (readwgts) {149if (isfvwgts)150graph->fvwgts = gk_fmalloc(nvtxs*ncon, "gk_graph_Read: fvwgts");151else152graph->ivwgts = gk_i32malloc(nvtxs*ncon, "gk_graph_Read: ivwgts");153}154155156/*----------------------------------------------------------------------157* Read the sparse graph file158*---------------------------------------------------------------------*/159numbering = (numbering ? - 1 : 0);160for (graph->xadj[0]=0, k=0, i=0; i<nvtxs; i++) {161do {162if (gk_getline(&line, &lnlen, fpin) == -1)163gk_errexit(SIGERR, "Pregraphure end of input file: file while reading row %d\n", i);164} while (line[0] == '%');165166head = line;167tail = NULL;168169/* Read vertex sizes */170if (readsizes) {171if (isfvsizes) {172#ifdef __MSC__173graph->fvsizes[i] = (float)strtod(head, &tail);174#else175graph->fvsizes[i] = strtof(head, &tail);176#endif177if (tail == head)178gk_errexit(SIGERR, "The line for vertex %zd does not have size information\n", i+1);179if (graph->fvsizes[i] < 0)180gk_errexit(SIGERR, "The size for vertex %zd must be >= 0\n", i+1);181}182else {183graph->ivsizes[i] = strtol(head, &tail, 0);184if (tail == head)185gk_errexit(SIGERR, "The line for vertex %zd does not have size information\n", i+1);186if (graph->ivsizes[i] < 0)187gk_errexit(SIGERR, "The size for vertex %zd must be >= 0\n", i+1);188}189head = tail;190}191192/* Read vertex weights */193if (readwgts) {194for (l=0; l<ncon; l++) {195if (isfvwgts) {196#ifdef __MSC__197graph->fvwgts[i*ncon+l] = (float)strtod(head, &tail);198#else199graph->fvwgts[i*ncon+l] = strtof(head, &tail);200#endif201if (tail == head)202gk_errexit(SIGERR, "The line for vertex %zd does not have enough weights "203"for the %d constraints.\n", i+1, ncon);204if (graph->fvwgts[i*ncon+l] < 0)205gk_errexit(SIGERR, "The weight vertex %zd and constraint %zd must be >= 0\n", i+1, l);206}207else {208graph->ivwgts[i*ncon+l] = strtol(head, &tail, 0);209if (tail == head)210gk_errexit(SIGERR, "The line for vertex %zd does not have enough weights "211"for the %d constraints.\n", i+1, ncon);212if (graph->ivwgts[i*ncon+l] < 0)213gk_errexit(SIGERR, "The weight vertex %zd and constraint %zd must be >= 0\n", i+1, l);214}215head = tail;216}217}218219220/* Read the rest of the row */221while (1) {222ival = (int)strtol(head, &tail, 0);223if (tail == head)224break;225head = tail;226227if ((graph->adjncy[k] = ival + numbering) < 0)228gk_errexit(SIGERR, "Error: Invalid column number %d at row %zd.\n", ival, i);229230if (readvals) {231if (isfewgts) {232#ifdef __MSC__233fval = (float)strtod(head, &tail);234#else235fval = strtof(head, &tail);236#endif237if (tail == head)238gk_errexit(SIGERR, "Value could not be found for edge! Vertex:%zd, NNZ:%zd\n", i, k);239240graph->fadjwgt[k] = fval;241}242else {243ival = strtol(head, &tail, 0);244if (tail == head)245gk_errexit(SIGERR, "Value could not be found for edge! Vertex:%zd, NNZ:%zd\n", i, k);246247graph->iadjwgt[k] = ival;248}249head = tail;250}251k++;252}253graph->xadj[i+1] = k;254}255256if (k != nedges)257gk_errexit(SIGERR, "gk_graph_Read: Something wrong with the number of edges in "258"the input file. nedges=%zd, Actualnedges=%zd.\n", nedges, k);259260gk_fclose(fpin);261262gk_free((void **)&line, LTERM);263264return graph;265}266267268/**************************************************************************/269/*! Writes a graph into a file.270\param graph is the graph to be written,271\param filename is the name of the output file.272\param format is one of GK_GRAPH_FMT_METIS specifying273the format of the output file.274*/275/**************************************************************************/276void gk_graph_Write(gk_graph_t *graph, char *filename, int format)277{278ssize_t i, j;279int hasvwgts, hasvsizes, hasewgts;280FILE *fpout;281282if (format != GK_GRAPH_FMT_METIS)283gk_errexit(SIGERR, "Unknown file format. %d\n", format);284285if (filename)286fpout = gk_fopen(filename, "w", "gk_graph_Write: fpout");287else288fpout = stdout;289290291hasewgts = (graph->iadjwgt || graph->fadjwgt);292hasvwgts = (graph->ivwgts || graph->fvwgts);293hasvsizes = (graph->ivsizes || graph->fvsizes);294295/* write the header line */296fprintf(fpout, "%d %zd", graph->nvtxs, graph->xadj[graph->nvtxs]/2);297if (hasvwgts || hasvsizes || hasewgts)298fprintf(fpout, " %d%d%d", hasvsizes, hasvwgts, hasewgts);299fprintf(fpout, "\n");300301302for (i=0; i<graph->nvtxs; i++) {303if (hasvsizes) {304if (graph->ivsizes)305fprintf(fpout, " %d", graph->ivsizes[i]);306else307fprintf(fpout, " %f", graph->fvsizes[i]);308}309310if (hasvwgts) {311if (graph->ivwgts)312fprintf(fpout, " %d", graph->ivwgts[i]);313else314fprintf(fpout, " %f", graph->fvwgts[i]);315}316317for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++) {318fprintf(fpout, " %d", graph->adjncy[j]+1);319if (hasewgts) {320if (graph->iadjwgt)321fprintf(fpout, " %d", graph->iadjwgt[j]);322else323fprintf(fpout, " %f", graph->fadjwgt[j]);324}325}326fprintf(fpout, "\n");327}328if (filename)329gk_fclose(fpout);330}331332333/*************************************************************************/334/*! Returns a copy of a graph.335\param graph is the graph to be duplicated.336\returns the newly created copy of the graph.337*/338/**************************************************************************/339gk_graph_t *gk_graph_Dup(gk_graph_t *graph)340{341gk_graph_t *ngraph;342343ngraph = gk_graph_Create();344345ngraph->nvtxs = graph->nvtxs;346347/* copy the adjacency structure */348if (graph->xadj)349ngraph->xadj = gk_zcopy(graph->nvtxs+1, graph->xadj,350gk_zmalloc(graph->nvtxs+1, "gk_graph_Dup: xadj"));351if (graph->ivwgts)352ngraph->ivwgts = gk_i32copy(graph->nvtxs, graph->ivwgts,353gk_i32malloc(graph->nvtxs, "gk_graph_Dup: ivwgts"));354if (graph->ivsizes)355ngraph->ivsizes = gk_i32copy(graph->nvtxs, graph->ivsizes,356gk_i32malloc(graph->nvtxs, "gk_graph_Dup: ivsizes"));357if (graph->vlabels)358ngraph->vlabels = gk_i32copy(graph->nvtxs, graph->vlabels,359gk_i32malloc(graph->nvtxs, "gk_graph_Dup: ivlabels"));360if (graph->fvwgts)361ngraph->fvwgts = gk_fcopy(graph->nvtxs, graph->fvwgts,362gk_fmalloc(graph->nvtxs, "gk_graph_Dup: fvwgts"));363if (graph->fvsizes)364ngraph->fvsizes = gk_fcopy(graph->nvtxs, graph->fvsizes,365gk_fmalloc(graph->nvtxs, "gk_graph_Dup: fvsizes"));366367368if (graph->adjncy)369ngraph->adjncy = gk_i32copy(graph->xadj[graph->nvtxs], graph->adjncy,370gk_i32malloc(graph->xadj[graph->nvtxs], "gk_graph_Dup: adjncy"));371if (graph->iadjwgt)372ngraph->iadjwgt = gk_i32copy(graph->xadj[graph->nvtxs], graph->iadjwgt,373gk_i32malloc(graph->xadj[graph->nvtxs], "gk_graph_Dup: iadjwgt"));374if (graph->fadjwgt)375ngraph->fadjwgt = gk_fcopy(graph->xadj[graph->nvtxs], graph->fadjwgt,376gk_fmalloc(graph->xadj[graph->nvtxs], "gk_graph_Dup: fadjwgt"));377378return ngraph;379}380381382/*************************************************************************/383/*! Returns a subgraph containing a set of consecutive vertices.384\param graph is the original graph.385\param vstart is the starting vertex.386\param nvtxs is the number of vertices from vstart to extract.387\returns the newly created subgraph.388*/389/**************************************************************************/390gk_graph_t *gk_graph_ExtractSubgraph(gk_graph_t *graph, int vstart, int nvtxs)391{392ssize_t i;393gk_graph_t *ngraph;394395if (vstart+nvtxs > graph->nvtxs)396return NULL;397398ngraph = gk_graph_Create();399400ngraph->nvtxs = nvtxs;401402/* copy the adjancy structure */403if (graph->xadj)404ngraph->xadj = gk_zcopy(nvtxs+1, graph->xadj+vstart,405gk_zmalloc(nvtxs+1, "gk_graph_ExtractSubgraph: xadj"));406for (i=nvtxs; i>=0; i--)407ngraph->xadj[i] -= ngraph->xadj[0];408ASSERT(ngraph->xadj[0] == 0);409410if (graph->ivwgts)411ngraph->ivwgts = gk_i32copy(nvtxs, graph->ivwgts+vstart,412gk_i32malloc(nvtxs, "gk_graph_ExtractSubgraph: ivwgts"));413if (graph->ivsizes)414ngraph->ivsizes = gk_i32copy(nvtxs, graph->ivsizes+vstart,415gk_i32malloc(nvtxs, "gk_graph_ExtractSubgraph: ivsizes"));416if (graph->vlabels)417ngraph->vlabels = gk_i32copy(nvtxs, graph->vlabels+vstart,418gk_i32malloc(nvtxs, "gk_graph_ExtractSubgraph: vlabels"));419420if (graph->fvwgts)421ngraph->fvwgts = gk_fcopy(nvtxs, graph->fvwgts+vstart,422gk_fmalloc(nvtxs, "gk_graph_ExtractSubgraph: fvwgts"));423if (graph->fvsizes)424ngraph->fvsizes = gk_fcopy(nvtxs, graph->fvsizes+vstart,425gk_fmalloc(nvtxs, "gk_graph_ExtractSubgraph: fvsizes"));426427428ASSERT(ngraph->xadj[nvtxs] == graph->xadj[vstart+nvtxs]-graph->xadj[vstart]);429if (graph->adjncy)430ngraph->adjncy = gk_i32copy(graph->xadj[vstart+nvtxs]-graph->xadj[vstart],431graph->adjncy+graph->xadj[vstart],432gk_i32malloc(graph->xadj[vstart+nvtxs]-graph->xadj[vstart],433"gk_graph_ExtractSubgraph: adjncy"));434if (graph->iadjwgt)435ngraph->iadjwgt = gk_i32copy(graph->xadj[vstart+nvtxs]-graph->xadj[vstart],436graph->iadjwgt+graph->xadj[vstart],437gk_i32malloc(graph->xadj[vstart+nvtxs]-graph->xadj[vstart],438"gk_graph_ExtractSubgraph: iadjwgt"));439if (graph->fadjwgt)440ngraph->fadjwgt = gk_fcopy(graph->xadj[vstart+nvtxs]-graph->xadj[vstart],441graph->fadjwgt+graph->xadj[vstart],442gk_fmalloc(graph->xadj[vstart+nvtxs]-graph->xadj[vstart],443"gk_graph_ExtractSubgraph: fadjwgt"));444445return ngraph;446}447448449/*************************************************************************/450/*! Returns a graph that has been reordered according to the permutation.451\param[IN] graph is the graph to be re-ordered.452\param[IN] perm is the new ordering of the graph's vertices453\param[IN] iperm is the original ordering of the re-ordered graph's vertices454\returns the newly created copy of the graph.455456\note Either perm or iperm can be NULL but not both.457*/458/**************************************************************************/459gk_graph_t *gk_graph_Reorder(gk_graph_t *graph, int32_t *perm, int32_t *iperm)460{461ssize_t j, jj, *xadj;462int i, k, u, v, nvtxs;463int freeperm=0, freeiperm=0;464int32_t *adjncy;465gk_graph_t *ngraph;466467if (perm == NULL && iperm == NULL)468return NULL;469470ngraph = gk_graph_Create();471472ngraph->nvtxs = nvtxs = graph->nvtxs;473xadj = graph->xadj;474adjncy = graph->adjncy;475476/* allocate memory for the different structures that are present in graph */477if (graph->xadj)478ngraph->xadj = gk_zmalloc(nvtxs+1, "gk_graph_Reorder: xadj");479480if (graph->ivwgts)481ngraph->ivwgts = gk_i32malloc(nvtxs, "gk_graph_Reorder: ivwgts");482483if (graph->ivsizes)484ngraph->ivsizes = gk_i32malloc(nvtxs, "gk_graph_Reorder: ivsizes");485486if (graph->vlabels)487ngraph->vlabels = gk_i32malloc(nvtxs, "gk_graph_Reorder: ivlabels");488489if (graph->fvwgts)490ngraph->fvwgts = gk_fmalloc(nvtxs, "gk_graph_Reorder: fvwgts");491492if (graph->fvsizes)493ngraph->fvsizes = gk_fmalloc(nvtxs, "gk_graph_Reorder: fvsizes");494495496if (graph->adjncy)497ngraph->adjncy = gk_i32malloc(graph->xadj[nvtxs], "gk_graph_Reorder: adjncy");498499if (graph->iadjwgt)500ngraph->iadjwgt = gk_i32malloc(graph->xadj[nvtxs], "gk_graph_Reorder: iadjwgt");501502if (graph->fadjwgt)503ngraph->fadjwgt = gk_fmalloc(graph->xadj[nvtxs], "gk_graph_Reorder: fadjwgt");504505506/* create perm/iperm if not provided */507if (perm == NULL) {508freeperm = 1;509perm = gk_i32malloc(nvtxs, "gk_graph_Reorder: perm");510for (i=0; i<nvtxs; i++)511perm[iperm[i]] = i;512}513if (iperm == NULL) {514freeiperm = 1;515iperm = gk_i32malloc(nvtxs, "gk_graph_Reorder: iperm");516for (i=0; i<nvtxs; i++)517iperm[perm[i]] = i;518}519520/* fill-in the information of the re-ordered graph */521ngraph->xadj[0] = jj = 0;522for (v=0; v<nvtxs; v++) {523u = iperm[v];524for (j=xadj[u]; j<xadj[u+1]; j++, jj++) {525ngraph->adjncy[jj] = perm[adjncy[j]];526if (graph->iadjwgt)527ngraph->iadjwgt[jj] = graph->iadjwgt[j];528if (graph->fadjwgt)529ngraph->fadjwgt[jj] = graph->fadjwgt[j];530}531if (graph->ivwgts)532ngraph->ivwgts[v] = graph->ivwgts[u];533if (graph->fvwgts)534ngraph->fvwgts[v] = graph->fvwgts[u];535if (graph->ivsizes)536ngraph->ivsizes[v] = graph->ivsizes[u];537if (graph->fvsizes)538ngraph->fvsizes[v] = graph->fvsizes[u];539if (graph->vlabels)540ngraph->vlabels[v] = graph->vlabels[u];541542ngraph->xadj[v+1] = jj;543}544545546/* free memory */547if (freeperm)548gk_free((void **)&perm, LTERM);549if (freeiperm)550gk_free((void **)&iperm, LTERM);551552return ngraph;553}554555556/*************************************************************************/557/*! This function finds the connected components in a graph.558559\param graph is the graph structure560\param cptr is the ptr structure of the CSR representation of the561components. The length of this vector must be graph->nvtxs+1.562\param cind is the indices structure of the CSR representation of563the components. The length of this vector must be graph->nvtxs.564565\returns the number of components that it found.566567\note The cptr and cind parameters can be NULL, in which case only the568number of connected components is returned.569*/570/*************************************************************************/571int gk_graph_FindComponents(gk_graph_t *graph, int32_t *cptr, int32_t *cind)572{573ssize_t i, ii, j, jj, k, nvtxs, first, last, ntodo, ncmps;574ssize_t *xadj;575int32_t *adjncy, *pos, *todo;576int32_t mustfree_ccsr=0, mustfree_where=0;577578nvtxs = graph->nvtxs;579xadj = graph->xadj;580adjncy = graph->adjncy;581582/* Deal with NULL supplied cptr/cind vectors */583if (cptr == NULL) {584cptr = gk_i32malloc(nvtxs+1, "gk_graph_FindComponents: cptr");585cind = gk_i32malloc(nvtxs, "gk_graph_FindComponents: cind");586mustfree_ccsr = 1;587}588589/* The list of vertices that have not been touched yet.590The valid entries are from [0..ntodo). */591todo = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "gk_graph_FindComponents: todo"));592593/* For a vertex that has not been visited, pos[i] is the position in the594todo list that this vertex is stored.595If a vertex has been visited, pos[i] = -1. */596pos = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "gk_graph_FindComponents: pos"));597598599/* Find the connected componends */600ncmps = -1;601ntodo = nvtxs; /* All vertices have not been visited */602first = last = 0; /* Point to the first and last vertices that have been touched603but not explored.604These vertices are stored in cind[first]...cind[last-1]. */605while (ntodo > 0) {606if (first == last) { /* Find another starting vertex */607cptr[++ncmps] = first; /* Mark the end of the current CC */608609ASSERT(pos[todo[0]] != -1);610i = todo[0];611612cind[last++] = i;613pos[i] = -1;614}615616i = cind[first++]; /* Get the first visited but unexplored vertex */617618/* Remove i from the todo list and put the last item in the todo619list at the position that i was so that the todo list will be620consequtive. The pos[] array is updated accordingly to keep track621the location of the vertices in the todo[] list. */622k = pos[i];623j = todo[k] = todo[--ntodo];624pos[j] = k;625626for (j=xadj[i]; j<xadj[i+1]; j++) {627k = adjncy[j];628if (pos[k] != -1) {629cind[last++] = k;630pos[k] = -1;631}632}633}634cptr[++ncmps] = first;635636if (mustfree_ccsr)637gk_free((void **)&cptr, &cind, LTERM);638639gk_free((void **)&pos, &todo, LTERM);640641return (int) ncmps;642}643644645/*************************************************************************/646/*! This function computes a permutation of the vertices based on a647breadth-first-traversal. It can be used for re-ordering the graph648to reduce its bandwidth for better cache locality.649The algorithm used is a simplified version of the method used to find650the connected components.651652\param[IN] graph is the graph structure653\param[IN] v is the starting vertex of the BFS654\param[OUT] perm[i] stores the ID of vertex i in the re-ordered graph.655\param[OUT] iperm[i] stores the ID of the vertex that corresponds to656the ith vertex in the re-ordered graph.657658\note The perm or iperm (but not both) can be NULL, at which point,659the corresponding arrays are not returned. Though the program660works fine when both are NULL, doing that is not smart.661The returned arrays should be freed with gk_free().662*/663/*************************************************************************/664void gk_graph_ComputeBFSOrdering(gk_graph_t *graph, int v, int32_t **r_perm,665int32_t **r_iperm)666{667ssize_t j, *xadj;668int i, k, nvtxs, first, last;669int32_t *adjncy, *cot, *pos;670671if (graph->nvtxs <= 0)672return;673674nvtxs = graph->nvtxs;675xadj = graph->xadj;676adjncy = graph->adjncy;677678/* This array will function like pos + touched of the CC method */679pos = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "gk_graph_ComputeBFSOrdering: pos"));680681/* This array ([C]losed[O]pen[T]odo => cot) serves three purposes.682Positions from [0...first) is the current iperm[] vector of the explored vertices;683Positions from [first...last) is the OPEN list (i.e., visited vertices);684Positions from [last...nvtxs) is the todo list. */685cot = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "gk_graph_ComputeBFSOrdering: cot"));686687688/* put v at the front of the todo list */689pos[0] = cot[0] = v;690pos[v] = cot[v] = 0;691692/* Find the connected componends induced by the partition */693first = last = 0;694while (first < nvtxs) {695if (first == last) { /* Find another starting vertex */696k = cot[last];697ASSERT(pos[k] != -1);698pos[k] = -1; /* mark node as being visited */699last++;700}701702i = cot[first++]; /* the ++ advances the explored vertices */703for (j=xadj[i]; j<xadj[i+1]; j++) {704k = adjncy[j];705/* if a node has already been visited, its perm[] will be -1 */706if (pos[k] != -1) {707/* pos[k] is the location within iperm of where k resides (it is in the 'todo' part);708It is placed in that location cot[last] (end of OPEN list) that we709are about to overwrite and update pos[cot[last]] to reflect that. */710cot[pos[k]] = cot[last]; /* put the head of the todo list to711where k was in the todo list */712pos[cot[last]] = pos[k]; /* update perm to reflect the move */713714cot[last++] = k; /* put node at the end of the OPEN list */715pos[k] = -1; /* mark node as being visited */716}717}718}719720/* time to decide what to return */721if (r_perm != NULL) {722/* use the 'pos' array to build the perm array */723for (i=0; i<nvtxs; i++)724pos[cot[i]] = i;725726*r_perm = pos;727pos = NULL;728}729730if (r_iperm != NULL) {731*r_iperm = cot;732cot = NULL;733}734735736/* cleanup memory */737gk_free((void **)&pos, &cot, LTERM);738739}740741742/*************************************************************************/743/*! This function computes a permutation of the vertices based on a744best-first-traversal. It can be used for re-ordering the graph745to reduce its bandwidth for better cache locality.746747\param[IN] graph is the graph structure.748\param[IN] v is the starting vertex of the best-first traversal.749\param[IN] type indicates the criteria to use to measure the 'bestness'750of a vertex.751\param[OUT] perm[i] stores the ID of vertex i in the re-ordered graph.752\param[OUT] iperm[i] stores the ID of the vertex that corresponds to753the ith vertex in the re-ordered graph.754755\note The perm or iperm (but not both) can be NULL, at which point,756the corresponding arrays are not returned. Though the program757works fine when both are NULL, doing that is not smart.758The returned arrays should be freed with gk_free().759*/760/*************************************************************************/761void gk_graph_ComputeBestFOrdering0(gk_graph_t *graph, int v, int type,762int32_t **r_perm, int32_t **r_iperm)763{764ssize_t j, jj, *xadj;765int i, k, u, nvtxs;766int32_t *adjncy, *perm, *degrees, *minIDs, *open;767gk_i32pq_t *queue;768769if (graph->nvtxs <= 0)770return;771772nvtxs = graph->nvtxs;773xadj = graph->xadj;774adjncy = graph->adjncy;775776/* the degree of the vertices in the closed list */777degrees = gk_i32smalloc(nvtxs, 0, "gk_graph_ComputeBestFOrdering: degrees");778779/* the minimum vertex ID of an open vertex to the closed list */780minIDs = gk_i32smalloc(nvtxs, nvtxs+1, "gk_graph_ComputeBestFOrdering: minIDs");781782/* the open list */783open = gk_i32malloc(nvtxs, "gk_graph_ComputeBestFOrdering: open");784785/* if perm[i] >= 0, then perm[i] is the order of vertex i;786otherwise perm[i] == -1.787*/788perm = gk_i32smalloc(nvtxs, -1, "gk_graph_ComputeBestFOrdering: perm");789790/* create the queue and put everything in it */791queue = gk_i32pqCreate(nvtxs);792for (i=0; i<nvtxs; i++)793gk_i32pqInsert(queue, i, 0);794gk_i32pqUpdate(queue, v, 1);795796open[0] = v;797798/* start processing the nodes */799for (i=0; i<nvtxs; i++) {800if ((v = gk_i32pqGetTop(queue)) == -1)801gk_errexit(SIGERR, "The priority queue got empty ahead of time [i=%d].\n", i);802if (perm[v] != -1)803gk_errexit(SIGERR, "The perm[%d] has already been set.\n", v);804perm[v] = i;805806807for (j=xadj[v]; j<xadj[v+1]; j++) {808u = adjncy[j];809if (perm[u] == -1) {810degrees[u]++;811minIDs[u] = (i < minIDs[u] ? i : minIDs[u]);812813switch (type) {814case 1: /* DFS */815gk_i32pqUpdate(queue, u, 1);816break;817case 2: /* Max in closed degree */818gk_i32pqUpdate(queue, u, degrees[u]);819break;820case 3: /* Sum of orders in closed list */821for (k=0, jj=xadj[u]; jj<xadj[u+1]; jj++) {822if (perm[adjncy[jj]] != -1)823k += perm[adjncy[jj]];824}825gk_i32pqUpdate(queue, u, k);826break;827case 4: /* Sum of order-differences (w.r.t. current number) in closed828list (updated once in a while) */829for (k=0, jj=xadj[u]; jj<xadj[u+1]; jj++) {830if (perm[adjncy[jj]] != -1)831k += (i-perm[adjncy[jj]]);832}833gk_i32pqUpdate(queue, u, k);834break;835default:836;837}838}839}840}841842843/* time to decide what to return */844if (r_perm != NULL) {845*r_perm = perm;846perm = NULL;847}848849if (r_iperm != NULL) {850/* use the 'degrees' array to build the iperm array */851for (i=0; i<nvtxs; i++)852degrees[perm[i]] = i;853854*r_iperm = degrees;855degrees = NULL;856}857858859860/* cleanup memory */861gk_i32pqDestroy(queue);862gk_free((void **)&perm, °rees, &minIDs, &open, LTERM);863864}865866867/*************************************************************************/868/*! This function computes a permutation of the vertices based on a869best-first-traversal. It can be used for re-ordering the graph870to reduce its bandwidth for better cache locality.871872\param[IN] graph is the graph structure.873\param[IN] v is the starting vertex of the best-first traversal.874\param[IN] type indicates the criteria to use to measure the 'bestness'875of a vertex.876\param[OUT] perm[i] stores the ID of vertex i in the re-ordered graph.877\param[OUT] iperm[i] stores the ID of the vertex that corresponds to878the ith vertex in the re-ordered graph.879880\note The perm or iperm (but not both) can be NULL, at which point,881the corresponding arrays are not returned. Though the program882works fine when both are NULL, doing that is not smart.883The returned arrays should be freed with gk_free().884*/885/*************************************************************************/886void gk_graph_ComputeBestFOrdering(gk_graph_t *graph, int v, int type,887int32_t **r_perm, int32_t **r_iperm)888{889ssize_t j, jj, *xadj;890int i, k, u, nvtxs, nopen, ntodo;891int32_t *adjncy, *perm, *degrees, *wdegrees, *sod, *level, *ot, *pos;892gk_i32pq_t *queue;893894if (graph->nvtxs <= 0)895return;896897nvtxs = graph->nvtxs;898xadj = graph->xadj;899adjncy = graph->adjncy;900901/* the degree of the vertices in the closed list */902degrees = gk_i32smalloc(nvtxs, 0, "gk_graph_ComputeBestFOrdering: degrees");903904/* the weighted degree of the vertices in the closed list for type==3 */905wdegrees = gk_i32smalloc(nvtxs, 0, "gk_graph_ComputeBestFOrdering: wdegrees");906907/* the sum of differences for type==4 */908sod = gk_i32smalloc(nvtxs, 0, "gk_graph_ComputeBestFOrdering: sod");909910/* the encountering level of a vertex type==5 */911level = gk_i32smalloc(nvtxs, 0, "gk_graph_ComputeBestFOrdering: level");912913/* The open+todo list of vertices.914The vertices from [0..nopen] are the open vertices.915The vertices from [nopen..ntodo) are the todo vertices.916*/917ot = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "gk_graph_FindComponents: ot"));918919/* For a vertex that has not been explored, pos[i] is the position in the ot list. */920pos = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "gk_graph_FindComponents: pos"));921922/* if perm[i] >= 0, then perm[i] is the order of vertex i; otherwise perm[i] == -1. */923perm = gk_i32smalloc(nvtxs, -1, "gk_graph_ComputeBestFOrdering: perm");924925/* create the queue and put the starting vertex in it */926queue = gk_i32pqCreate(nvtxs);927gk_i32pqInsert(queue, v, 1);928929/* put v at the front of the open list */930pos[0] = ot[0] = v;931pos[v] = ot[v] = 0;932nopen = 1;933ntodo = nvtxs;934935/* start processing the nodes */936for (i=0; i<nvtxs; i++) {937if (nopen == 0) { /* deal with non-connected graphs */938gk_i32pqInsert(queue, ot[0], 1);939nopen++;940}941942if ((v = gk_i32pqGetTop(queue)) == -1)943gk_errexit(SIGERR, "The priority queue got empty ahead of time [i=%d].\n", i);944945if (perm[v] != -1)946gk_errexit(SIGERR, "The perm[%d] has already been set.\n", v);947perm[v] = i;948949if (ot[pos[v]] != v)950gk_errexit(SIGERR, "Something went wrong [ot[pos[%d]]!=%d.\n", v, v);951if (pos[v] >= nopen)952gk_errexit(SIGERR, "The position of v is not in open list. pos[%d]=%d is >=%d.\n", v, pos[v], nopen);953954/* remove v from the open list and re-arrange the todo part of the list */955ot[pos[v]] = ot[nopen-1];956pos[ot[nopen-1]] = pos[v];957if (ntodo > nopen) {958ot[nopen-1] = ot[ntodo-1];959pos[ot[ntodo-1]] = nopen-1;960}961nopen--;962ntodo--;963964for (j=xadj[v]; j<xadj[v+1]; j++) {965u = adjncy[j];966if (perm[u] == -1) {967/* update ot list, if u is not in the open list by putting it at the end968of the open list. */969if (degrees[u] == 0) {970ot[pos[u]] = ot[nopen];971pos[ot[nopen]] = pos[u];972ot[nopen] = u;973pos[u] = nopen;974nopen++;975976level[u] = level[v]+1;977gk_i32pqInsert(queue, u, 0);978}979980981/* update the in-closed degree */982degrees[u]++;983984/* update the queues based on the type */985switch (type) {986case 1: /* DFS */987gk_i32pqUpdate(queue, u, 1000*(i+1)+degrees[u]);988break;989990case 2: /* Max in closed degree */991gk_i32pqUpdate(queue, u, degrees[u]);992break;993994case 3: /* Sum of orders in closed list */995wdegrees[u] += i;996gk_i32pqUpdate(queue, u, wdegrees[u]);997break;998999case 4: /* Sum of order-differences */1000/* this is handled at the end of the loop */1001;1002break;10031004case 5: /* BFS with in degree priority */1005gk_i32pqUpdate(queue, u, -(1000*level[u] - degrees[u]));1006break;10071008case 6: /* Hybrid of 1+2 */1009gk_i32pqUpdate(queue, u, (i+1)*degrees[u]);1010break;10111012default:1013;1014}1015}1016}10171018if (type == 4) { /* update all the vertices in the open list */1019for (j=0; j<nopen; j++) {1020u = ot[j];1021if (perm[u] != -1)1022gk_errexit(SIGERR, "For i=%d, the open list contains a closed vertex: ot[%zd]=%d, perm[%d]=%d.\n", i, j, u, u, perm[u]);1023sod[u] += degrees[u];1024if (i<1000 || i%25==0)1025gk_i32pqUpdate(queue, u, sod[u]);1026}1027}10281029/*1030for (j=0; j<ntodo; j++) {1031if (pos[ot[j]] != j)1032gk_errexit(SIGERR, "pos[ot[%zd]] != %zd.\n", j, j);1033}1034*/10351036}103710381039/* time to decide what to return */1040if (r_perm != NULL) {1041*r_perm = perm;1042perm = NULL;1043}10441045if (r_iperm != NULL) {1046/* use the 'degrees' array to build the iperm array */1047for (i=0; i<nvtxs; i++)1048degrees[perm[i]] = i;10491050*r_iperm = degrees;1051degrees = NULL;1052}1053105410551056/* cleanup memory */1057gk_i32pqDestroy(queue);1058gk_free((void **)&perm, °rees, &wdegrees, &sod, &ot, &pos, &level, LTERM);10591060}106110621063/*************************************************************************/1064/*! This function computes the single-source shortest path lengths from the1065root node to all the other nodes in the graph. If the graph is not1066connected then, the sortest part to the vertices in the other components1067is -1.10681069\param[IN] graph is the graph structure.1070\param[IN] v is the root of the single-source shortest path computations.1071\param[IN] type indicates the criteria to use to measure the 'bestness'1072of a vertex.1073\param[OUT] sps[i] stores the length of the shortest path from v to vertex i.1074If no such path exists, then it is -1. Note that the returned1075array will be either an array of int32_t or an array of floats.1076The specific type is determined by the existance of non NULL1077iadjwgt and fadjwgt arrays. If both of these arrays exist, then1078priority is given to iadjwgt.10791080\note The returned array should be freed with gk_free().1081*/1082/*************************************************************************/1083void gk_graph_SingleSourceShortestPaths(gk_graph_t *graph, int v, void **r_sps)1084{1085ssize_t *xadj;1086int i, u, nvtxs;1087int32_t *adjncy, *inqueue;10881089if (graph->nvtxs <= 0)1090return;10911092nvtxs = graph->nvtxs;1093xadj = graph->xadj;1094adjncy = graph->adjncy;10951096inqueue = gk_i32smalloc(nvtxs, 0, "gk_graph_SingleSourceShortestPaths: inqueue");10971098/* determine if you will be computing using int32_t or float and proceed from there */1099if (graph->iadjwgt != NULL) {1100gk_i32pq_t *queue;1101int32_t *adjwgt;1102int32_t *sps;11031104adjwgt = graph->iadjwgt;11051106queue = gk_i32pqCreate(nvtxs);1107gk_i32pqInsert(queue, v, 0);1108inqueue[v] = 1;11091110sps = gk_i32smalloc(nvtxs, -1, "gk_graph_SingleSourceShortestPaths: sps");1111sps[v] = 0;11121113/* start processing the nodes */1114while ((v = gk_i32pqGetTop(queue)) != -1) {1115inqueue[v] = 2;11161117/* relax the adjacent edges */1118for (i=xadj[v]; i<xadj[v+1]; i++) {1119u = adjncy[i];1120if (inqueue[u] == 2)1121continue;11221123if (sps[u] < 0 || sps[v]+adjwgt[i] < sps[u]) {1124sps[u] = sps[v]+adjwgt[i];11251126if (inqueue[u])1127gk_i32pqUpdate(queue, u, -sps[u]);1128else {1129gk_i32pqInsert(queue, u, -sps[u]);1130inqueue[u] = 1;1131}1132}1133}1134}11351136*r_sps = (void *)sps;11371138gk_i32pqDestroy(queue);1139}1140else {1141gk_fpq_t *queue;1142float *adjwgt;1143float *sps;11441145adjwgt = graph->fadjwgt;11461147queue = gk_fpqCreate(nvtxs);1148gk_fpqInsert(queue, v, 0);1149inqueue[v] = 1;11501151sps = gk_fsmalloc(nvtxs, -1, "gk_graph_SingleSourceShortestPaths: sps");1152sps[v] = 0;11531154/* start processing the nodes */1155while ((v = gk_fpqGetTop(queue)) != -1) {1156inqueue[v] = 2;11571158/* relax the adjacent edges */1159for (i=xadj[v]; i<xadj[v+1]; i++) {1160u = adjncy[i];1161if (inqueue[u] == 2)1162continue;11631164if (sps[u] < 0 || sps[v]+adjwgt[i] < sps[u]) {1165sps[u] = sps[v]+adjwgt[i];11661167if (inqueue[u])1168gk_fpqUpdate(queue, u, -sps[u]);1169else {1170gk_fpqInsert(queue, u, -sps[u]);1171inqueue[u] = 1;1172}1173}1174}1175}11761177*r_sps = (void *)sps;11781179gk_fpqDestroy(queue);1180}11811182gk_free((void **)&inqueue, LTERM);11831184}1185118611871188#ifdef XXX11891190/*************************************************************************/1191/*! Sorts the adjacency lists in increasing vertex order1192\param graph the graph itself,1193*/1194/**************************************************************************/1195void gk_graph_SortAdjacencies(gk_graph_t *graph)1196{1197int n, nn=0;1198ssize_t *ptr;1199int *ind;1200float *val;12011202switch (what) {1203case GK_CSR_ROW:1204if (!graph->rowptr)1205gk_errexit(SIGERR, "Row-based view of the graphrix does not exists.\n");12061207n = graph->nrows;1208ptr = graph->rowptr;1209ind = graph->rowind;1210val = graph->rowval;1211break;12121213case GK_CSR_COL:1214if (!graph->colptr)1215gk_errexit(SIGERR, "Column-based view of the graphrix does not exists.\n");12161217n = graph->ncols;1218ptr = graph->colptr;1219ind = graph->colind;1220val = graph->colval;1221break;12221223default:1224gk_errexit(SIGERR, "Invalid index type of %d.\n", what);1225return;1226}12271228#pragma omp parallel if (n > 100)1229{1230ssize_t i, j, k;1231gk_ikv_t *cand;1232float *tval;12331234#pragma omp single1235for (i=0; i<n; i++)1236nn = gk_max(nn, ptr[i+1]-ptr[i]);12371238cand = gk_ikvmalloc(nn, "gk_graph_SortIndices: cand");1239tval = gk_fmalloc(nn, "gk_graph_SortIndices: tval");12401241#pragma omp for schedule(static)1242for (i=0; i<n; i++) {1243for (k=0, j=ptr[i]; j<ptr[i+1]; j++) {1244if (j > ptr[i] && ind[j] < ind[j-1])1245k = 1; /* an inversion */1246cand[j-ptr[i]].val = j-ptr[i];1247cand[j-ptr[i]].key = ind[j];1248tval[j-ptr[i]] = val[j];1249}1250if (k) {1251gk_ikvsorti(ptr[i+1]-ptr[i], cand);1252for (j=ptr[i]; j<ptr[i+1]; j++) {1253ind[j] = cand[j-ptr[i]].key;1254val[j] = tval[cand[j-ptr[i]].val];1255}1256}1257}12581259gk_free((void **)&cand, &tval, LTERM);1260}12611262}126312641265/*************************************************************************/1266/*! Returns a subgraphrix containing a certain set of rows.1267\param graph is the original graphrix.1268\param nrows is the number of rows to extract.1269\param rind is the set of row numbers to extract.1270\returns the row structure of the newly created subgraphrix.1271*/1272/**************************************************************************/1273gk_graph_t *gk_graph_ExtractRows(gk_graph_t *graph, int nrows, int *rind)1274{1275ssize_t i, ii, j, nnz;1276gk_graph_t *ngraph;12771278ngraph = gk_graph_Create();12791280ngraph->nrows = nrows;1281ngraph->ncols = graph->ncols;12821283for (nnz=0, i=0; i<nrows; i++)1284nnz += graph->rowptr[rind[i]+1]-graph->rowptr[rind[i]];12851286ngraph->rowptr = gk_zmalloc(ngraph->nrows+1, "gk_graph_ExtractPartition: rowptr");1287ngraph->rowind = gk_imalloc(nnz, "gk_graph_ExtractPartition: rowind");1288ngraph->rowval = gk_fmalloc(nnz, "gk_graph_ExtractPartition: rowval");12891290ngraph->rowptr[0] = 0;1291for (nnz=0, j=0, ii=0; ii<nrows; ii++) {1292i = rind[ii];1293gk_icopy(graph->rowptr[i+1]-graph->rowptr[i], graph->rowind+graph->rowptr[i], ngraph->rowind+nnz);1294gk_fcopy(graph->rowptr[i+1]-graph->rowptr[i], graph->rowval+graph->rowptr[i], ngraph->rowval+nnz);1295nnz += graph->rowptr[i+1]-graph->rowptr[i];1296ngraph->rowptr[++j] = nnz;1297}1298ASSERT(j == ngraph->nrows);12991300return ngraph;1301}130213031304/*************************************************************************/1305/*! Returns a subgraphrix corresponding to a specified partitioning of rows.1306\param graph is the original graphrix.1307\param part is the partitioning vector of the rows.1308\param pid is the partition ID that will be extracted.1309\returns the row structure of the newly created subgraphrix.1310*/1311/**************************************************************************/1312gk_graph_t *gk_graph_ExtractPartition(gk_graph_t *graph, int *part, int pid)1313{1314ssize_t i, j, nnz;1315gk_graph_t *ngraph;13161317ngraph = gk_graph_Create();13181319ngraph->nrows = 0;1320ngraph->ncols = graph->ncols;13211322for (nnz=0, i=0; i<graph->nrows; i++) {1323if (part[i] == pid) {1324ngraph->nrows++;1325nnz += graph->rowptr[i+1]-graph->rowptr[i];1326}1327}13281329ngraph->rowptr = gk_zmalloc(ngraph->nrows+1, "gk_graph_ExtractPartition: rowptr");1330ngraph->rowind = gk_imalloc(nnz, "gk_graph_ExtractPartition: rowind");1331ngraph->rowval = gk_fmalloc(nnz, "gk_graph_ExtractPartition: rowval");13321333ngraph->rowptr[0] = 0;1334for (nnz=0, j=0, i=0; i<graph->nrows; i++) {1335if (part[i] == pid) {1336gk_icopy(graph->rowptr[i+1]-graph->rowptr[i], graph->rowind+graph->rowptr[i], ngraph->rowind+nnz);1337gk_fcopy(graph->rowptr[i+1]-graph->rowptr[i], graph->rowval+graph->rowptr[i], ngraph->rowval+nnz);1338nnz += graph->rowptr[i+1]-graph->rowptr[i];1339ngraph->rowptr[++j] = nnz;1340}1341}1342ASSERT(j == ngraph->nrows);13431344return ngraph;1345}134613471348/*************************************************************************/1349/*! Splits the graphrix into multiple sub-graphrices based on the provided1350color array.1351\param graph is the original graphrix.1352\param color is an array of size equal to the number of non-zeros1353in the graphrix (row-wise structure). The graphrix is split into1354as many parts as the number of colors. For meaningfull results,1355the colors should be numbered consecutively starting from 0.1356\returns an array of graphrices for each supplied color number.1357*/1358/**************************************************************************/1359gk_graph_t **gk_graph_Split(gk_graph_t *graph, int *color)1360{1361ssize_t i, j;1362int nrows, ncolors;1363ssize_t *rowptr;1364int *rowind;1365float *rowval;1366gk_graph_t **sgraphs;13671368nrows = graph->nrows;1369rowptr = graph->rowptr;1370rowind = graph->rowind;1371rowval = graph->rowval;13721373ncolors = gk_imax(rowptr[nrows], color)+1;13741375sgraphs = (gk_graph_t **)gk_malloc(sizeof(gk_graph_t *)*ncolors, "gk_graph_Split: sgraphs");1376for (i=0; i<ncolors; i++) {1377sgraphs[i] = gk_graph_Create();1378sgraphs[i]->nrows = graph->nrows;1379sgraphs[i]->ncols = graph->ncols;1380sgraphs[i]->rowptr = gk_zsmalloc(nrows+1, 0, "gk_graph_Split: sgraphs[i]->rowptr");1381}13821383for (i=0; i<nrows; i++) {1384for (j=rowptr[i]; j<rowptr[i+1]; j++)1385sgraphs[color[j]]->rowptr[i]++;1386}1387for (i=0; i<ncolors; i++)1388MAKECSR(j, nrows, sgraphs[i]->rowptr);13891390for (i=0; i<ncolors; i++) {1391sgraphs[i]->rowind = gk_imalloc(sgraphs[i]->rowptr[nrows], "gk_graph_Split: sgraphs[i]->rowind");1392sgraphs[i]->rowval = gk_fmalloc(sgraphs[i]->rowptr[nrows], "gk_graph_Split: sgraphs[i]->rowval");1393}13941395for (i=0; i<nrows; i++) {1396for (j=rowptr[i]; j<rowptr[i+1]; j++) {1397sgraphs[color[j]]->rowind[sgraphs[color[j]]->rowptr[i]] = rowind[j];1398sgraphs[color[j]]->rowval[sgraphs[color[j]]->rowptr[i]] = rowval[j];1399sgraphs[color[j]]->rowptr[i]++;1400}1401}14021403for (i=0; i<ncolors; i++)1404SHIFTCSR(j, nrows, sgraphs[i]->rowptr);14051406return sgraphs;1407}140814091410/*************************************************************************/1411/*! Prunes certain rows/columns of the graphrix. The prunning takes place1412by analyzing the row structure of the graphrix. The prunning takes place1413by removing rows/columns but it does not affect the numbering of the1414remaining rows/columns.14151416\param graph the graphrix to be prunned,1417\param what indicates if the rows (GK_CSR_ROW) or the columns (GK_CSR_COL)1418of the graphrix will be prunned,1419\param minf is the minimum number of rows (columns) that a column (row) must1420be present in order to be kept,1421\param maxf is the maximum number of rows (columns) that a column (row) must1422be present at in order to be kept.1423\returns the prunned graphrix consisting only of its row-based structure.1424The input graphrix is not modified.1425*/1426/**************************************************************************/1427gk_graph_t *gk_graph_Prune(gk_graph_t *graph, int what, int minf, int maxf)1428{1429ssize_t i, j, nnz;1430int nrows, ncols;1431ssize_t *rowptr, *nrowptr;1432int *rowind, *nrowind, *collen;1433float *rowval, *nrowval;1434gk_graph_t *ngraph;14351436ngraph = gk_graph_Create();14371438nrows = ngraph->nrows = graph->nrows;1439ncols = ngraph->ncols = graph->ncols;14401441rowptr = graph->rowptr;1442rowind = graph->rowind;1443rowval = graph->rowval;14441445nrowptr = ngraph->rowptr = gk_zmalloc(nrows+1, "gk_graph_Prune: nrowptr");1446nrowind = ngraph->rowind = gk_imalloc(rowptr[nrows], "gk_graph_Prune: nrowind");1447nrowval = ngraph->rowval = gk_fmalloc(rowptr[nrows], "gk_graph_Prune: nrowval");144814491450switch (what) {1451case GK_CSR_COL:1452collen = gk_ismalloc(ncols, 0, "gk_graph_Prune: collen");14531454for (i=0; i<nrows; i++) {1455for (j=rowptr[i]; j<rowptr[i+1]; j++) {1456ASSERT(rowind[j] < ncols);1457collen[rowind[j]]++;1458}1459}1460for (i=0; i<ncols; i++)1461collen[i] = (collen[i] >= minf && collen[i] <= maxf ? 1 : 0);14621463nrowptr[0] = 0;1464for (nnz=0, i=0; i<nrows; i++) {1465for (j=rowptr[i]; j<rowptr[i+1]; j++) {1466if (collen[rowind[j]]) {1467nrowind[nnz] = rowind[j];1468nrowval[nnz] = rowval[j];1469nnz++;1470}1471}1472nrowptr[i+1] = nnz;1473}1474gk_free((void **)&collen, LTERM);1475break;14761477case GK_CSR_ROW:1478nrowptr[0] = 0;1479for (nnz=0, i=0; i<nrows; i++) {1480if (rowptr[i+1]-rowptr[i] >= minf && rowptr[i+1]-rowptr[i] <= maxf) {1481for (j=rowptr[i]; j<rowptr[i+1]; j++, nnz++) {1482nrowind[nnz] = rowind[j];1483nrowval[nnz] = rowval[j];1484}1485}1486nrowptr[i+1] = nnz;1487}1488break;14891490default:1491gk_graph_Free(&ngraph);1492gk_errexit(SIGERR, "Unknown prunning type of %d\n", what);1493return NULL;1494}14951496return ngraph;1497}1498149915001501/*************************************************************************/1502/*! Normalizes the rows/columns of the graphrix to be unit1503length.1504\param graph the graphrix itself,1505\param what indicates what will be normalized and is obtained by1506specifying GK_CSR_ROW, GK_CSR_COL, GK_CSR_ROW|GK_CSR_COL.1507\param norm indicates what norm is to normalize to, 1: 1-norm, 2: 2-norm1508*/1509/**************************************************************************/1510void gk_graph_Normalize(gk_graph_t *graph, int what, int norm)1511{1512ssize_t i, j;1513int n;1514ssize_t *ptr;1515float *val, sum;15161517if (what&GK_CSR_ROW && graph->rowval) {1518n = graph->nrows;1519ptr = graph->rowptr;1520val = graph->rowval;15211522#pragma omp parallel if (ptr[n] > OMPMINOPS)1523{1524#pragma omp for private(j,sum) schedule(static)1525for (i=0; i<n; i++) {1526for (sum=0.0, j=ptr[i]; j<ptr[i+1]; j++){1527if (norm == 2)1528sum += val[j]*val[j];1529else if (norm == 1)1530sum += val[j]; /* assume val[j] > 0 */1531}1532if (sum > 0) {1533if (norm == 2)1534sum=1.0/sqrt(sum);1535else if (norm == 1)1536sum=1.0/sum;1537for (j=ptr[i]; j<ptr[i+1]; j++)1538val[j] *= sum;15391540}1541}1542}1543}15441545if (what&GK_CSR_COL && graph->colval) {1546n = graph->ncols;1547ptr = graph->colptr;1548val = graph->colval;15491550#pragma omp parallel if (ptr[n] > OMPMINOPS)1551{1552#pragma omp for private(j,sum) schedule(static)1553for (i=0; i<n; i++) {1554for (sum=0.0, j=ptr[i]; j<ptr[i+1]; j++)1555if (norm == 2)1556sum += val[j]*val[j];1557else if (norm == 1)1558sum += val[j];1559if (sum > 0) {1560if (norm == 2)1561sum=1.0/sqrt(sum);1562else if (norm == 1)1563sum=1.0/sum;1564for (j=ptr[i]; j<ptr[i+1]; j++)1565val[j] *= sum;1566}1567}1568}1569}1570}157115721573#endif157415751576