Merge lp:~taynaud/gephi/statistics-correction into lp:~gephi.team/gephi/0.8

Proposed by Thomas Aynaud
Status: Merged
Approved by: Sébastien Heymann
Approved revision: 2224
Merge reported by: Sébastien Heymann
Merged at revision: not available
Proposed branch: lp:~taynaud/gephi/statistics-correction
Merge into: lp:~gephi.team/gephi/0.8
Diff against target: 163 lines (+14/-39)
1 file modified
StatisticsPlugin/src/org/gephi/statistics/plugin/Modularity.java (+14/-39)
To merge this branch: bzr merge lp:~taynaud/gephi/statistics-correction
Reviewer Review Type Date Requested Status
Sébastien Heymann Approve
Review via email: mp+61108@code.launchpad.net

Description of the change

Correct a bug in modularity optimisation.

The Louvain algorithm study node one by one, and for each node :

remove it from its community
look for any neighboring community and select the one which maximizes modularity gain
put the node into this community.

The implemented algorithm was not removing the node from its community, resulting in a wrong gain computation. Now, the algorithm still not remove the node from its community (which would be slow with the current implementation) but compute the gain accurately.

There was also an issue with self loops counted twice.

To post a comment you must log in.
Revision history for this message
Sébastien Heymann (sebastien.heymann) :
review: Approve
Revision history for this message
Sébastien Heymann (sebastien.heymann) wrote :

Merged on rev 2222

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'StatisticsPlugin/src/org/gephi/statistics/plugin/Modularity.java'
--- StatisticsPlugin/src/org/gephi/statistics/plugin/Modularity.java 2011-04-07 17:40:45 +0000
+++ StatisticsPlugin/src/org/gephi/statistics/plugin/Modularity.java 2011-05-16 12:56:49 +0000
@@ -96,6 +96,7 @@
96 int N;96 int N;
97 HashMap<Integer, Community> invMap;97 HashMap<Integer, Community> invMap;
9898
99
99 CommunityStructure(HierarchicalUndirectedGraph hgraph) {100 CommunityStructure(HierarchicalUndirectedGraph hgraph) {
100 this.graph = hgraph;101 this.graph = hgraph;
101 N = hgraph.getNodeCount();102 N = hgraph.getNodeCount();
@@ -116,9 +117,8 @@
116 Community hidden = new Community(structure);117 Community hidden = new Community(structure);
117 hidden.nodes.add(index);118 hidden.nodes.add(index);
118 invMap.put(index, hidden);119 invMap.put(index, hidden);
119 communities.add(nodeCommunities[index]);120 communities.add(nodeCommunities[index]);
120 index++;121 index++;
121
122 if (isCanceled) {122 if (isCanceled) {
123 return;123 return;
124 }124 }
@@ -140,7 +140,7 @@
140 nodeCommunities[node_index].connections.put(adjCom, 1);140 nodeCommunities[node_index].connections.put(adjCom, 1);
141 nodeConnections[neighbor_index].put(nodeCommunities[node_index], 1);141 nodeConnections[neighbor_index].put(nodeCommunities[node_index], 1);
142 nodeCommunities[neighbor_index].connections.put(nodeCommunities[node_index], 1);142 nodeCommunities[neighbor_index].connections.put(nodeCommunities[node_index], 1);
143 graphWeightSum++;143 graphWeightSum++;//WARNING : may be an issue with self_loop
144 }144 }
145145
146 if (isCanceled) {146 if (isCanceled) {
@@ -275,8 +275,10 @@
275 for(Community adjCom : iter) {275 for(Community adjCom : iter) {
276 int target = communities.indexOf(adjCom);276 int target = communities.indexOf(adjCom);
277 int weight = com.connections.get(adjCom);277 int weight = com.connections.get(adjCom);
278278 if(target == index)
279 weightSum += weight;279 weightSum += 2*weight;
280 else
281 weightSum += weight;
280 ModEdge e = new ModEdge(index, target, weight);282 ModEdge e = new ModEdge(index, target, weight);
281 newTopology[index].add(e);283 newTopology[index].add(e);
282 }284 }
@@ -304,12 +306,10 @@
304 }306 }
305307
306 class Community {308 class Community {
307
308 double weightSum;309 double weightSum;
309 CommunityStructure structure;310 CommunityStructure structure;
310 LinkedList<Integer> nodes;311 LinkedList<Integer> nodes;
311 HashMap<Community, Integer> connections;312 HashMap<Community, Integer> connections;
312 Integer min;
313313
314 public int size() {314 public int size() {
315 return nodes.size();315 return nodes.size();
@@ -319,7 +319,6 @@
319 structure = com.structure;319 structure = com.structure;
320 connections = new HashMap<Community, Integer>();320 connections = new HashMap<Community, Integer>();
321 nodes = new LinkedList<Integer>();321 nodes = new LinkedList<Integer>();
322 min = Integer.MAX_VALUE;
323 //mHidden = pCom.mHidden;322 //mHidden = pCom.mHidden;
324 }323 }
325324
@@ -332,15 +331,11 @@
332 public void seed(int node) {331 public void seed(int node) {
333 nodes.add(node);332 nodes.add(node);
334 weightSum += structure.weights[node];333 weightSum += structure.weights[node];
335 min = node;
336 }334 }
337335
338 public boolean add(int node) {336 public boolean add(int node) {
339 nodes.addLast(new Integer(node));337 nodes.addLast(new Integer(node));
340 weightSum += structure.weights[node];338 weightSum += structure.weights[node];
341 if (!isRandomized) {
342 min = Math.min(node, min);
343 }
344 return true;339 return true;
345 }340 }
346341
@@ -350,20 +345,8 @@
350 if (nodes.size() == 0) {345 if (nodes.size() == 0) {
351 structure.communities.remove(this);346 structure.communities.remove(this);
352 }347 }
353 if (!isRandomized) {
354 if (node == min.intValue()) {
355 min = Integer.MAX_VALUE;
356 for (Integer other : nodes) {
357 min = Math.min(other, min);
358 }
359 }
360 }
361 return result;348 return result;
362 }349 }
363
364 public int getMin() {
365 return min;
366 }
367 }350 }
368351
369 public void execute(GraphModel graphModel, AttributeModel attributeModel) {352 public void execute(GraphModel graphModel, AttributeModel attributeModel) {
@@ -375,9 +358,7 @@
375 isCanceled = false;358 isCanceled = false;
376 Progress.start(progress);359 Progress.start(progress);
377 Random rand = new Random();360 Random rand = new Random();
378
379 hgraph.readLock();361 hgraph.readLock();
380
381 structure = new CommunityStructure(hgraph);362 structure = new CommunityStructure(hgraph);
382 if (isCanceled) {363 if (isCanceled) {
383 hgraph.readUnlockAll();364 hgraph.readUnlockAll();
@@ -387,8 +368,6 @@
387 while (someChange) {368 while (someChange) {
388 someChange = false;369 someChange = false;
389 boolean localChange = true;370 boolean localChange = true;
390
391
392 while (localChange) {371 while (localChange) {
393 localChange = false;372 localChange = false;
394 int start = 0;373 int start = 0;
@@ -398,22 +377,16 @@
398 int step = 0;377 int step = 0;
399 for (int i = start; step < structure.N; i = (i + 1) % structure.N) {378 for (int i = start; step < structure.N; i = (i + 1) % structure.N) {
400 step++;379 step++;
401 double best = 0;380 double best = 0.;
402 double current = q(i, structure.nodeCommunities[i]);
403 Community bestCommunity = null;381 Community bestCommunity = null;
404 int smallest = Integer.MAX_VALUE;382 Community nodecom = structure.nodeCommunities[i];
405 Set<Community> iter = structure.nodeConnections[i].keySet();383 Set<Community> iter = structure.nodeConnections[i].keySet();
406 for(Community com : iter) {384 for(Community com : iter) {
407 double qValue = q(i, com) - current;385 double qValue = q(i, com);
408 if (qValue > best) {386 if (qValue > best) {
409 best = qValue;387 best = qValue;
410 bestCommunity = com;388 bestCommunity = com;
411 smallest = com.getMin();389 }
412 } else if ((qValue == best) && (com.getMin() < smallest)) {
413 best = qValue;
414 bestCommunity = com;
415 smallest = com.getMin();
416 }
417 }390 }
418 if ((structure.nodeCommunities[i] != bestCommunity) && (bestCommunity != null)) {391 if ((structure.nodeCommunities[i] != bestCommunity) && (bestCommunity != null)) {
419 structure.moveNodeTo(i, bestCommunity);392 structure.moveNodeTo(i, bestCommunity);
@@ -518,11 +491,13 @@
518 }491 }
519 double weightSum = community.weightSum;492 double weightSum = community.weightSum;
520 double nodeWeight = structure.weights[node];493 double nodeWeight = structure.weights[node];
521 //double penalty = (nodeWeight * weightSum) / (2.0 * mStructure.graphWeightSum);
522 double qValue = edgesTo - (nodeWeight * weightSum) / (2.0 * structure.graphWeightSum);494 double qValue = edgesTo - (nodeWeight * weightSum) / (2.0 * structure.graphWeightSum);
523 if ((structure.nodeCommunities[node] == community) && (structure.nodeCommunities[node].size() > 1)) {495 if ((structure.nodeCommunities[node] == community) && (structure.nodeCommunities[node].size() > 1)) {
524 qValue = edgesTo - (nodeWeight * (weightSum - nodeWeight)) / (2.0 * structure.graphWeightSum);496 qValue = edgesTo - (nodeWeight * (weightSum - nodeWeight)) / (2.0 * structure.graphWeightSum);
525 }497 }
498 if ((structure.nodeCommunities[node] == community) && (structure.nodeCommunities[node].size() == 1)) {
499 qValue = 0.;
500 }
526 return qValue;501 return qValue;
527 }502 }
528}503}

Subscribers

People subscribed via source and target branches