From 40a5126078b2764232e165e55aaa92f4446b3f79 Mon Sep 17 00:00:00 2001 From: Samuh <quentin@liane.net> Date: Wed, 24 Mar 2021 15:14:14 +0100 Subject: [PATCH] =?UTF-8?q?Compatibilit=C3=A9=20windows-autre?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- louvain-master/louvain.c | 4 +- louvain-master/partition.c | 334 +++++++++++++++++++++---------------- 2 files changed, 196 insertions(+), 142 deletions(-) diff --git a/louvain-master/louvain.c b/louvain-master/louvain.c index 669385f..dbff451 100644 --- a/louvain-master/louvain.c +++ b/louvain-master/louvain.c @@ -16,7 +16,9 @@ // Version Windows -#define bzero(b,len) (memset((b), '\0', (len)), (void) 0) +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) + #define bzero(b,len) (memset((b), '\0', (len)), (void) 0) +#endif //compute the maximum of three unsigned long diff --git a/louvain-master/partition.c b/louvain-master/partition.c index de9f9c5..19b6c64 100644 --- a/louvain-master/partition.c +++ b/louvain-master/partition.c @@ -2,84 +2,100 @@ #define NLINKS2 8 -int myCompare (const void * a, const void * b, void * array2) { +int myCompare(const void *a, const void *b, void *array2) +{ long diff = ((unsigned long *)array2)[*(unsigned long *)a] - ((unsigned long *)array2)[*(unsigned *)b]; int res = (0 < diff) - (diff < 0); - return res; + return res; } -int myCompare_W (void * array2, const void * a, const void * b) { +int myCompare_W(void *array2, const void *a, const void *b) +{ long diff = ((unsigned long *)array2)[*(unsigned long *)a] - ((unsigned long *)array2)[*(unsigned *)b]; int res = (0 < diff) - (diff < 0); - return res; + return res; } -unsigned long * mySort(unsigned long *part, unsigned long size) { +unsigned long *mySort(unsigned long *part, unsigned long size) +{ unsigned long i; unsigned long *nodes = (unsigned long *)malloc(size * sizeof(unsigned long)); - for (i = 0; i < size; i++) { - nodes[i]=i; + for (i = 0; i < size; i++) + { + nodes[i] = i; } - // qsort_r(nodes, size, sizeof(unsigned long), myCompare, (void *)part); +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) qsort_s(nodes, size, sizeof(unsigned long), myCompare_W, (void *)part); +#else + qsort_r(nodes, size, sizeof(unsigned long), myCompare, (void *)part); +#endif return nodes; } - - -inline long double degreeWeighted(adjlist *g, unsigned long node) { +inline long double degreeWeighted(adjlist *g, unsigned long node) +{ unsigned long long i; - if (g->weights == NULL) { - return 1.*(g->cd[node + 1] - g->cd[node]); + if (g->weights == NULL) + { + return 1. * (g->cd[node + 1] - g->cd[node]); } long double res = 0.0L; - for (i = g->cd[node]; i < g->cd[node + 1]; i++) { + for (i = g->cd[node]; i < g->cd[node + 1]; i++) + { res += g->weights[i]; } return res; } -inline long double selfloopWeighted(adjlist *g, unsigned long node) { +inline long double selfloopWeighted(adjlist *g, unsigned long node) +{ unsigned long long i; - for (i = g->cd[node]; i < g->cd[node + 1]; i++) { - if (g->adj[i] == node) { - return (g->weights == NULL)?1.0:g->weights[i]; + for (i = g->cd[node]; i < g->cd[node + 1]; i++) + { + if (g->adj[i] == node) + { + return (g->weights == NULL) ? 1.0 : g->weights[i]; } } return 0.0; } -inline void removeNode(louvainPartition *p, adjlist *g, unsigned long node, unsigned long comm, long double dnodecomm) { - p->in[comm] -= 2.0L * dnodecomm + selfloopWeighted(g, node); +inline void removeNode(louvainPartition *p, adjlist *g, unsigned long node, unsigned long comm, long double dnodecomm) +{ + p->in[comm] -= 2.0L * dnodecomm + selfloopWeighted(g, node); p->tot[comm] -= degreeWeighted(g, node); } -inline void insertNode(louvainPartition *p, adjlist *g, unsigned long node, unsigned long comm, long double dnodecomm) { - p->in[comm] += 2.0L * dnodecomm + selfloopWeighted(g, node); +inline void insertNode(louvainPartition *p, adjlist *g, unsigned long node, unsigned long comm, long double dnodecomm) +{ + p->in[comm] += 2.0L * dnodecomm + selfloopWeighted(g, node); p->tot[comm] += degreeWeighted(g, node); - + p->node2Community[node] = comm; } -inline long double gain(louvainPartition *p, adjlist *g, unsigned long comm, long double dnc, long double degc) { +inline long double gain(louvainPartition *p, adjlist *g, unsigned long comm, long double dnc, long double degc) +{ long double totc = p->tot[comm]; - long double m2 = g->totalWeight; - - return (dnc - totc*degc/m2); + long double m2 = g->totalWeight; + + return (dnc - totc * degc / m2); } //freeing memory -void free_adjlist2(adjlist *g){ +void free_adjlist2(adjlist *g) +{ free(g->cd); free(g->adj); free(g->weights); free(g); } -void freeLouvainPartition(louvainPartition *p) { +void freeLouvainPartition(louvainPartition *p) +{ free(p->in); free(p->tot); free(p->neighCommWeights); @@ -88,8 +104,8 @@ void freeLouvainPartition(louvainPartition *p) { free(p); } - -louvainPartition *createLouvainPartition(adjlist *g) { +louvainPartition *createLouvainPartition(adjlist *g) +{ unsigned long i; louvainPartition *p = malloc(sizeof(louvainPartition)); @@ -104,9 +120,10 @@ louvainPartition *createLouvainPartition(adjlist *g) { p->neighCommPos = malloc(p->size * sizeof(unsigned long)); p->neighCommNb = 0; - for (i = 0; i < p->size; i++) { + for (i = 0; i < p->size; i++) + { p->node2Community[i] = i; - p->in[i] = selfloopWeighted(g, i); + p->in[i] = selfloopWeighted(g, i); p->tot[i] = degreeWeighted(g, i); p->neighCommWeights[i] = -1; p->neighCommPos[i] = 0; @@ -115,12 +132,14 @@ louvainPartition *createLouvainPartition(adjlist *g) { return p; } -long double modularity(louvainPartition *p, adjlist *g) { - long double q = 0.0L; +long double modularity(louvainPartition *p, adjlist *g) +{ + long double q = 0.0L; long double m2 = g->totalWeight; unsigned long i; - for (i = 0; i < p->size; i++) { + for (i = 0; i < p->size; i++) + { if (p->tot[i] > 0.0L) q += p->in[i] - (p->tot[i] * p->tot[i]) / m2; } @@ -128,9 +147,11 @@ long double modularity(louvainPartition *p, adjlist *g) { return q / m2; } -void neighCommunitiesInit(louvainPartition *p) { +void neighCommunitiesInit(louvainPartition *p) +{ unsigned long i; - for (i = 0; i < p->neighCommNb; i++) { + for (i = 0; i < p->neighCommNb; i++) + { p->neighCommWeights[p->neighCommPos[i]] = -1; } p->neighCommNb = 0; @@ -139,7 +160,8 @@ void neighCommunitiesInit(louvainPartition *p) { /* Computes the set of neighbor communities of a given node (excluding self-loops) */ -void neighCommunities(louvainPartition *p, adjlist *g, unsigned long node) { +void neighCommunities(louvainPartition *p, adjlist *g, unsigned long node) +{ unsigned long long i; unsigned long neigh, neighComm; long double neighW; @@ -148,18 +170,21 @@ void neighCommunities(louvainPartition *p, adjlist *g, unsigned long node) { p->neighCommNb = 1; // for all neighbors of node, add weight to the corresponding community - for (i = g->cd[node]; i < g->cd[node + 1]; i++) { - neigh = g->adj[i]; + for (i = g->cd[node]; i < g->cd[node + 1]; i++) + { + neigh = g->adj[i]; neighComm = p->node2Community[neigh]; - neighW = (g->weights == NULL)?1.0:g->weights[i]; + neighW = (g->weights == NULL) ? 1.0 : g->weights[i]; // if not a self-loop - if (neigh != node) { + if (neigh != node) + { // if community is new (weight == -1) - if (p->neighCommWeights[neighComm] == -1) { - p->neighCommPos[p->neighCommNb] = neighComm; - p->neighCommWeights[neighComm] = 0.; - p->neighCommNb++; + if (p->neighCommWeights[neighComm] == -1) + { + p->neighCommPos[p->neighCommNb] = neighComm; + p->neighCommWeights[neighComm] = 0.; + p->neighCommNb++; } p->neighCommWeights[neighComm] += neighW; } @@ -171,67 +196,76 @@ Same behavior as neighCommunities except: - self loop are counted - data structure if not reinitialised */ -void neighCommunitiesAll(louvainPartition *p, adjlist *g, unsigned long node) { +void neighCommunitiesAll(louvainPartition *p, adjlist *g, unsigned long node) +{ unsigned long long i; unsigned long neigh, neighComm; long double neighW; - for (i = g->cd[node]; i < g->cd[node + 1]; i++) { - neigh = g->adj[i]; + for (i = g->cd[node]; i < g->cd[node + 1]; i++) + { + neigh = g->adj[i]; neighComm = p->node2Community[neigh]; - neighW = (g->weights == NULL)?1.0:g->weights[i]; - + neighW = (g->weights == NULL) ? 1.0 : g->weights[i]; + // if community is new - if (p->neighCommWeights[neighComm] == -1) { + if (p->neighCommWeights[neighComm] == -1) + { p->neighCommPos[p->neighCommNb] = neighComm; - p->neighCommWeights[neighComm] = 0.; + p->neighCommWeights[neighComm] = 0.; p->neighCommNb++; } p->neighCommWeights[neighComm] += neighW; } } - -unsigned long updatePartition(louvainPartition *p, unsigned long *part, unsigned long size) { +unsigned long updatePartition(louvainPartition *p, unsigned long *part, unsigned long size) +{ // Renumber the communities in p unsigned long *renumber = calloc(p->size, sizeof(unsigned long)); unsigned long i, last = 1; - for (i = 0; i < p->size; i++) { - if (renumber[p->node2Community[i]] == 0) { + for (i = 0; i < p->size; i++) + { + if (renumber[p->node2Community[i]] == 0) + { renumber[p->node2Community[i]] = last++; } } // Update part with the renumbered communities in p - for (i = 0; i < size; i++) { + for (i = 0; i < size; i++) + { part[i] = renumber[p->node2Community[part[i]]] - 1; } free(renumber); - return last-1; + return last - 1; } - // Return the meta graph induced by a partition of a graph // See Louvain article for more details -adjlist* louvainPartition2Graph(louvainPartition *p, adjlist *g) { +adjlist *louvainPartition2Graph(louvainPartition *p, adjlist *g) +{ unsigned long node, i, j; // Renumber communities unsigned long *renumber = (unsigned long *)malloc(g->n * sizeof(unsigned long)); for (node = 0; node < g->n; node++) renumber[node] = 0; unsigned long last = 1; - for (node = 0; node < g->n; node++) { - if (renumber[p->node2Community[node]] == 0) { + for (node = 0; node < g->n; node++) + { + if (renumber[p->node2Community[node]] == 0) + { renumber[p->node2Community[node]] = last++; } } - for (node = 0; node < g->n; node++) { - p->node2Community[node] = renumber[p->node2Community[node]] - 1 ; + for (node = 0; node < g->n; node++) + { + p->node2Community[node] = renumber[p->node2Community[node]] - 1; } // sort nodes according to their community - unsigned long * order = mySort(p->node2Community, g->n); + unsigned long *order = mySort(p->node2Community, g->n); // displayPartU(p->node2Community, g->n); // Initialize meta graph @@ -247,53 +281,58 @@ adjlist* louvainPartition2Graph(louvainPartition *p, adjlist *g) { // for each node (in community order), extract all edges to other communities and build the graph neighCommunitiesInit(p); - unsigned long oldComm = p->node2Community[order[0]];//renumber[p->node2Community[order[0]]]; + unsigned long oldComm = p->node2Community[order[0]]; //renumber[p->node2Community[order[0]]]; unsigned long currentComm; - for (i = 0; i <= p->size; i++) { + for (i = 0; i <= p->size; i++) + { // current node and current community with dummy values if out of bounds - node = (i == p->size)?0:order[i]; - currentComm = (i == p->size)?currentComm + 1:p->node2Community[order[i]]; - + node = (i == p->size) ? 0 : order[i]; + currentComm = (i == p->size) ? currentComm + 1 : p->node2Community[order[i]]; + // new community, write previous one - if (oldComm != currentComm) { + if (oldComm != currentComm) + { res->cd[oldComm + 1] = res->cd[oldComm] + p->neighCommNb; // displayPartU(res->degrees, res->n + 1); // for all neighboring communities of current community - for (j = 0; j < p->neighCommNb; j++) { - unsigned long neighComm = p->neighCommPos[j]; - long double neighCommWeight = p->neighCommWeights[p->neighCommPos[j]]; - - // add edge in res - res->adj[res->e] = neighComm; - res->weights[res->e] = neighCommWeight; - res->totalWeight += neighCommWeight; - (res->e)++; - - // reallocate edges and weights if necessary - if (res->e == e1) { - e1 *= 2; - res->adj = (unsigned long *)realloc(res->adj, e1 * sizeof(unsigned long)); - res->weights = (long double *)realloc(res->weights, e1 * sizeof(long double)); - if (res->adj == NULL || res->weights == NULL) { - printf("error during memory allocation\n"); - exit(0); - } - } - + for (j = 0; j < p->neighCommNb; j++) + { + unsigned long neighComm = p->neighCommPos[j]; + long double neighCommWeight = p->neighCommWeights[p->neighCommPos[j]]; + + // add edge in res + res->adj[res->e] = neighComm; + res->weights[res->e] = neighCommWeight; + res->totalWeight += neighCommWeight; + (res->e)++; + + // reallocate edges and weights if necessary + if (res->e == e1) + { + e1 *= 2; + res->adj = (unsigned long *)realloc(res->adj, e1 * sizeof(unsigned long)); + res->weights = (long double *)realloc(res->weights, e1 * sizeof(long double)); + if (res->adj == NULL || res->weights == NULL) + { + printf("error during memory allocation\n"); + exit(0); + } + } } // display(res); - if (i == p->size) { - res->adj = (unsigned long *)realloc(res->adj, res->e * sizeof(unsigned long)); - res->weights = (long double *)realloc(res->weights, res->e * sizeof(long double)); + if (i == p->size) + { + res->adj = (unsigned long *)realloc(res->adj, res->e * sizeof(unsigned long)); + res->weights = (long double *)realloc(res->weights, res->e * sizeof(long double)); - free(order); - free(renumber); + free(order); + free(renumber); - return res; + return res; } oldComm = currentComm; @@ -310,31 +349,33 @@ adjlist* louvainPartition2Graph(louvainPartition *p, adjlist *g) { } // Compute one pass of Louvain and returns the improvement -long double louvainOneLevel(louvainPartition *p, adjlist *g) { +long double louvainOneLevel(louvainPartition *p, adjlist *g) +{ unsigned long nbMoves; long double startModularity = modularity(p, g); long double newModularity = startModularity; long double curModularity; - unsigned long i,j,node; - unsigned long oldComm,newComm,bestComm; + unsigned long i, j, node; + unsigned long oldComm, newComm, bestComm; long double degreeW, bestCommW, bestGain, newGain; - // generate a random order for nodes' movements unsigned long *randomOrder = (unsigned long *)malloc(p->size * sizeof(unsigned long)); for (unsigned long i = 0; i < p->size; i++) randomOrder[i] = i; - for (unsigned long i = 0; i < p->size - 1; i++) { - unsigned long randPos = rand()%(p->size - i) + i; - unsigned long tmp = randomOrder[i]; + for (unsigned long i = 0; i < p->size - 1; i++) + { + unsigned long randPos = rand() % (p->size - i) + i; + unsigned long tmp = randomOrder[i]; randomOrder[i] = randomOrder[randPos]; randomOrder[randPos] = tmp; } - - // repeat while + + // repeat while // there are some nodes moving - // or there is an improvement of quality greater than a given epsilon - do { + // or there is an improvement of quality greater than a given epsilon + do + { curModularity = newModularity; nbMoves = 0; @@ -342,8 +383,9 @@ long double louvainOneLevel(louvainPartition *p, adjlist *g) { // remove the node from its community // compute the gain for its insertion in all neighboring communities // insert it in the best community with the highest gain - for (i = 0; i < g->n; i++) { - node = i;//randomOrder[nodeTmp]; + for (i = 0; i < g->n; i++) + { + node = i; //randomOrder[nodeTmp]; oldComm = p->node2Community[node]; degreeW = degreeWeighted(g, node); @@ -357,24 +399,27 @@ long double louvainOneLevel(louvainPartition *p, adjlist *g) { // compute the gain for all neighboring communities // default choice is the former community bestComm = oldComm; - bestCommW = 0.0L; + bestCommW = 0.0L; bestGain = 0.0L; - for (j = 0; j < p->neighCommNb; j++) { - newComm = p->neighCommPos[j]; - newGain = gain(p, g, newComm, p->neighCommWeights[newComm], degreeW); - - if (newGain > bestGain) { - bestComm = newComm; - bestCommW = p->neighCommWeights[newComm]; - bestGain = newGain; - } + for (j = 0; j < p->neighCommNb; j++) + { + newComm = p->neighCommPos[j]; + newGain = gain(p, g, newComm, p->neighCommWeights[newComm], degreeW); + + if (newGain > bestGain) + { + bestComm = newComm; + bestCommW = p->neighCommWeights[newComm]; + bestGain = newGain; + } } // insert node in the nearest community insertNode(p, g, node, bestComm, bestCommW); - if (bestComm != oldComm) { - nbMoves++; + if (bestComm != oldComm) + { + nbMoves++; } } @@ -382,19 +427,21 @@ long double louvainOneLevel(louvainPartition *p, adjlist *g) { // printf("%Lf\n", newModularity); - } while (nbMoves>0 && - newModularity - curModularity > MIN_IMPROVEMENT); - + } while (nbMoves > 0 && + newModularity - curModularity > MIN_IMPROVEMENT); + free(randomOrder); return newModularity - startModularity; } -unsigned long louvain(adjlist *g, unsigned long *lab) { - unsigned long i,n; +unsigned long louvain(adjlist *g, unsigned long *lab) +{ + unsigned long i, n; long double improvement; // Initialize partition with trivial communities - for (i = 0; i < g->n; i++) { + for (i = 0; i < g->n; i++) + { lab[i] = i; } @@ -406,44 +453,49 @@ unsigned long louvain(adjlist *g, unsigned long *lab) { return n; } -unsigned long louvainComplete(adjlist *g, unsigned long *lab) { +unsigned long louvainComplete(adjlist *g, unsigned long *lab) +{ adjlist *init = g, *g2; unsigned long n, i; unsigned long long j; unsigned long originalSize = g->n; long double improvement; // Initialize partition with trivial communities - for (i = 0; i < g->n; i++) { + for (i = 0; i < g->n; i++) + { lab[i] = i; } // Execution of Louvain method - while(1) { + while (1) + { louvainPartition *gp = createLouvainPartition(g); - + improvement = louvainOneLevel(gp, g); - + n = updatePartition(gp, lab, originalSize); - if (improvement < MIN_IMPROVEMENT) { + if (improvement < MIN_IMPROVEMENT) + { freeLouvainPartition(gp); break; } - + g2 = louvainPartition2Graph(gp, g); // free all graphs except the original one - if (g->n < originalSize) { + if (g->n < originalSize) + { free_adjlist2(g); } freeLouvainPartition(gp); g = g2; } - if (g->n < originalSize) { + if (g->n < originalSize) + { free_adjlist2(g); } return n; } - -- GitLab