diff --git a/html/admin/js/graphViewer/graph/modularityJoiner.js b/html/admin/js/graphViewer/graph/modularityJoiner.js
index ad80112f39..f710cbc31d 100644
--- a/html/admin/js/graphViewer/graph/modularityJoiner.js
+++ b/html/admin/js/graphViewer/graph/modularityJoiner.js
@@ -99,6 +99,9 @@ function ModularityJoiner(nodes, edges) {
delDQVal = function(i, j) {
if (i < j) {
+ if (!dQ[i]) {
+ return;
+ }
delete dQ[i][j];
if (_.isEmpty(dQ[i])) {
delete dQ[i];
@@ -400,7 +403,7 @@ function ModularityJoiner(nodes, edges) {
////////////////////////////////////
// computation //
////////////////////////////////////
-
+
this.joinCommunity = function(comm) {
var s = comm.sID,
l = comm.lID,
diff --git a/html/admin/js/graphViewer/jasmine_test/helper/objectsHelper.js b/html/admin/js/graphViewer/jasmine_test/helper/objectsHelper.js
index 23cf48227e..2b1ff11569 100644
--- a/html/admin/js/graphViewer/jasmine_test/helper/objectsHelper.js
+++ b/html/admin/js/graphViewer/jasmine_test/helper/objectsHelper.js
@@ -38,7 +38,7 @@ var helper = helper || {};
var i;
for (i = 0; i < n; i++) {
nodes.push({
- _id: i,
+ _id: String(i),
_inboundCounter: 0,
_outboundCounter: 0,
position: {
diff --git a/html/admin/js/graphViewer/jasmine_test/specNodeReducer/modularityJoinerSpec.js b/html/admin/js/graphViewer/jasmine_test/specNodeReducer/modularityJoinerSpec.js
index d7bb6986cb..2408536b9e 100644
--- a/html/admin/js/graphViewer/jasmine_test/specNodeReducer/modularityJoinerSpec.js
+++ b/html/admin/js/graphViewer/jasmine_test/specNodeReducer/modularityJoinerSpec.js
@@ -321,6 +321,45 @@
expect(joiner.getDQ()).toEqual(expected);
});
+ it('should be ordered', function() {
+ this.addMatchers({
+ toBeOrdered: function() {
+ var dQ = this.actual,
+ notFailed = true,
+ msg = "The pointers: ";
+ _.each(dQ, function(list, pointer) {
+ _.each(list, function(val, target) {
+ if (target < pointer) {
+ notFailed = false;
+ msg += pointer + " -> " + target + ", ";
+ }
+ });
+ });
+ this.message = function() {
+ return msg + "are not correct";
+ };
+ return notFailed;
+ }
+ });
+
+ var firstID = nodes.length;
+ helper.insertSimpleNodes(nodes, ["9", "20", "10", "99", "12"]);
+
+ edges.push(helper.createSimpleEdge(nodes, 0, firstID));
+ edges.push(helper.createSimpleEdge(nodes, firstID, firstID + 1));
+ edges.push(helper.createSimpleEdge(nodes, firstID + 1, firstID + 2));
+ edges.push(helper.createSimpleEdge(nodes, firstID + 2, firstID + 3));
+ edges.push(helper.createSimpleEdge(nodes, firstID + 3, firstID + 4));
+ edges.push(helper.createSimpleEdge(nodes, firstID + 4, firstID));
+ edges.push(helper.createSimpleEdge(nodes, firstID + 3, firstID));
+
+ joiner.setup();
+
+ var dQ = joiner.getDQ();
+ expect(dQ).toBeOrdered();
+
+ });
+
});
describe('the heap', function() {
@@ -667,32 +706,224 @@
});
- /*
- describe('checking large networks', function() {
+ describe('checking consistency after join', function() {
- it('should be able to handle 1000 nodes', function() {
- var i, best
- helper.insertNSimpleNodes(nodes, 1000);
+ beforeEach(function() {
+ this.addMatchers({
+ toBeOrdered: function(failedIn) {
+ var dQ = this.actual,
+ notFailed = true,
+ msg = "Step " + failedIn + ": In dQ the pointers: ";
+ _.each(dQ, function(list, pointer) {
+ _.each(list, function(val, target) {
+ if (target < pointer) {
+ notFailed = false;
+ msg += pointer + " -> " + target + ", ";
+ }
+ });
+ });
+ this.message = function() {
+ return msg + "are not correct";
+ };
+ return notFailed;
+ },
+
+ toFulfillHeapConstraint: function(joined) {
+ var heap = this.actual.getHeap(),
+ high = joined.lID;
+ this.message = function() {
+ return "The heap " + _.keys(heap) + " should not contain " + high;
+ };
+ return _.isUndefined(heap[high]);
+ },
+ toFulfillDQConstraint: function(joined) {
+ var dQ = this.actual.getDQ(),
+ high = joined.lID;
+ this.message = function() {
+ return "The delta Q " + _.keys(dQ) + " should not contain " + high;
+ };
+ return _.isUndefined(dQ[high]);
+ },
+ toBeDefinedInHeapIffInDQ: function(testee) {
+ var id = this.actual,
+ dQ = testee.getDQ(),
+ heap = testee.getHeap();
+ if (_.isUndefined(dQ[id])) {
+ this.message = id + " is defined on heap but not on dQ";
+ return _.isUndefined(heap[id]);
+ }
+ this.message = id + " is defined on dQ but not on heap";
+ return !_.isUndefined(heap[id]);
+ },
+ toFulfillCommunityInclusionConstraint: function(joined) {
+ var comms = this.actual.getCommunities(),
+ low = joined.sID,
+ high = joined.lID;
+ if (_.isUndefined(comms[low])) {
+ this.message = function() {
+ return "The lower ID " + low + " is no pointer to a community";
+ }
+ return false;
+ }
+ this.message = function() {
+ return "The community " + comms[low].nodes + " should contain " + high;
+ };
+ return _.contains(comms[low].nodes, high);
+ },
+
+ toFulfillCommunityPointerConstraint: function() {
+ var comms = this.actual.getCommunities(),
+ notFailed = true,
+ msg = "In communities the pointers: "
+ _.each(comms, function(list, pointer) {
+ var ns = list.nodes;
+ if (ns[0] !== pointer) {
+ notFailed = false;
+ msg += pointer + " -first-> " + ns[0] + ", ";
+ }
+ _.each(ns, function(id) {
+ if (id < pointer) {
+ notFailed = false;
+ msg += pointer + " -> " + id + ", ";
+ }
+ });
+ });
+ this.message = function () {
+ return msg += "are not correct";
+ }
+ return notFailed;
+ },
+
+ toNotContainAnyJoinedNode: function() {
+ var comms = this.actual.getCommunities(),
+ dQ = this.actual.getDQ(),
+ forbidden = [],
+ msg = "Nodes: ",
+ notFailed = true;
+ _.each(comms, function(list) {
+ var reducedList = list.nodes.slice();
+ reducedList.shift(1);
+ forbidden = forbidden.concat(reducedList);
+ });
+ _.each(forbidden, function (id) {
+ if (!_.isUndefined(dQ[id])) {
+ notFailed = false;
+ msg += id + ", ";
+ }
+ });
+ this.message = function() {
+ return msg + "should not be contained in dQ";
+ };
+ return notFailed;
+
+ },
+
+ toBeConsistent: function(joined, failedIn) {
+ var testee = this.actual;
+ expect(testee).toFulfillDQConstraint(joined);
+ expect(testee).toFulfillHeapConstraint(joined);
+ expect(joined.sID).toBeDefinedInHeapIffInDQ(testee);
+ expect(testee).toFulfillCommunityInclusionConstraint(joined);
+ expect(testee).toNotContainAnyJoinedNode();
+ expect(testee).toFulfillCommunityPointerConstraint();
+
+ return true;
+ },
+
+ toContainALowerAndAHigherID: function() {
+ var toJoin = this.actual;
+ this.message = function() {
+ return toJoin.sID + " shold be lower than " + toJoin.lID;
+ };
+ return toJoin.sID < toJoin.lID;
+ }
+
+ });
+ });
+
+ it('for a larger network', function() {
+ var i, best,
+ step = 0,
+ nodeCount = 20;
+ helper.insertNSimpleNodes(nodes, nodeCount);
helper.insertClique(nodes, edges, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
- for (i = 11; i < 1000; i++) {
+ for (i = 11; i < nodeCount; i++) {
edges.push(helper.createSimpleEdge(nodes, i - 1, i));
edges.push(helper.createSimpleEdge(nodes, i, i - 2));
}
-
joiner.setup();
best = joiner.getBest();
var step = 0;
+ while (best !== null) {
+ expect(best).toContainALowerAndAHigherID();
+ joiner.joinCommunity(best);
+ expect(joiner).toBeConsistent(best, step);
+ best = joiner.getBest();
+ step++;
+ }
+ });
+
+ });
+
+
+ describe('checking large networks', function() {
+
+ it('should be able to handle 1000 nodes', function() {
+ var start = (new Date).getTime();
+ var i, best, nodeCount = 1000;
+ helper.insertNSimpleNodes(nodes, nodeCount);
+ helper.insertClique(nodes, edges, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+ for (i = 11; i < nodeCount; i++) {
+ edges.push(helper.createSimpleEdge(nodes, i - 1, i));
+ edges.push(helper.createSimpleEdge(nodes, i, i - 2));
+ }
+ var diff = (new Date).getTime() - start;
+ console.log("Runtime Fill:", diff, "ms");
+ start = (new Date).getTime();
+ joiner.setup();
+ diff = (new Date).getTime() - start;
+ console.log("Runtime Setup:", diff, "ms");
+ start = (new Date).getTime();
+ best = joiner.getBest();
+ var step = 0;
while (best !== null) {
joiner.joinCommunity(best);
best = joiner.getBest();
step++;
}
- //expect(joiner.getCommunities()).toContainKarateClubCommunities();
-
+ diff = (new Date).getTime() - start;
+ console.log("Runtime Compute:", diff, "ms");
});
-
+ /*
+ it('should be able to handle 10000 nodes', function() {
+ var start = (new Date).getTime();
+ var i, best, nodeCount = 10000;
+ helper.insertNSimpleNodes(nodes, nodeCount);
+ helper.insertClique(nodes, edges, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+ for (i = 11; i < nodeCount; i++) {
+ edges.push(helper.createSimpleEdge(nodes, i - 1, i));
+ edges.push(helper.createSimpleEdge(nodes, i, i - 2));
+ }
+ var diff = (new Date).getTime() - start;
+ console.log("Runtime Fill:", diff, "ms");
+ start = (new Date).getTime();
+ joiner.setup();
+ diff = (new Date).getTime() - start;
+ console.log("Runtime Setup:", diff, "ms");
+ start = (new Date).getTime();
+ best = joiner.getBest();
+ var step = 0;
+ while (best !== null) {
+ joiner.joinCommunity(best);
+ best = joiner.getBest();
+ step++;
+ }
+ diff = (new Date).getTime() - start;
+ console.log("Runtime Compute:", diff, "ms");
+ });
+ */
});
- */
+
});
});
}());
\ No newline at end of file