1
0
Fork 0

GraphViewer: ModularityJoiner is now independet from the nodes, just relying on edges. Did speed up setup process as iteration is only over connected nodes

This commit is contained in:
Michael Hackstein 2013-07-05 13:15:55 +02:00
parent 2b7bb78fa6
commit 2d16ac415e
2 changed files with 80 additions and 184 deletions

View File

@ -27,17 +27,16 @@
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany /// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
function ModularityJoiner(nodes, edges) { function ModularityJoiner(edges) {
"use strict"; "use strict";
if (nodes === undefined) {
throw "Nodes have to be given.";
}
if (edges === undefined) { if (edges === undefined) {
throw "Edges have to be given."; throw "Edges have to be given.";
} }
var matrix = null, var matrix = null,
backwardMatrix,
degrees = null,
m = 0, m = 0,
revM = 0, revM = 0,
a = null, a = null,
@ -149,11 +148,19 @@ function ModularityJoiner(nodes, edges) {
makeAdjacencyMatrix = function() { makeAdjacencyMatrix = function() {
matrix = {}; matrix = {};
backwardMatrix = {};
degrees = {};
_.each(edges, function (e) { _.each(edges, function (e) {
var s = e.source._id, var s = e.source._id,
t = e.target._id; t = e.target._id;
matrix[s] = matrix[s] || {}; matrix[s] = matrix[s] || {};
matrix[s][t] = (matrix[s][t] || 0) + 1; matrix[s][t] = (matrix[s][t] || 0) + 1;
backwardMatrix[t] = backwardMatrix[t] || {};
backwardMatrix[t][s] = (backwardMatrix[t][s] || 0) + 1;
degrees[s] = degrees[s] || {_in: 0, _out:0};
degrees[t] = degrees[t] || {_in: 0, _out:0};
degrees[s]._out++;
degrees[t]._in++;
}); });
m = edges.length; m = edges.length;
revM = 1/m; revM = 1/m;
@ -162,66 +169,34 @@ function ModularityJoiner(nodes, edges) {
makeInitialDegrees = function() { makeInitialDegrees = function() {
a = {}; a = {};
_.each(nodes, function (n) { _.each(degrees, function (n, id) {
a[n._id] = { a[id] = {
_in: n._inboundCounter / m, _in: n._in / m,
_out: n._outboundCounter / m _out: n._out / m
}; };
}); });
return a; return a;
}, },
makeInitialDQBKP = function() {
dQ = {};
_.each(nodes, function(n1) {
var s = n1._id;
_.each(nodes, function(n2) {
var t = n2._id,
ast;
if (matrix[s] && matrix[s][t]) {
ast = matrix[s][t];
} else {
ast = 0;
}
if (s < t) {
dQ[s] = dQ[s] || {};
dQ[s][t] = (dQ[s][t] || 0) + ast * revM - a[s]._in * a[t]._out;
return;
}
if (t < s) {
dQ[t] = dQ[t] || {};
dQ[t][s] = (dQ[t][s] || 0) + ast * revM - a[s]._in * a[t]._out;
return;
}
});
});
},
notConnectedPenalty = function(s, t) { notConnectedPenalty = function(s, t) {
return a[s]._out * a[t]._in + a[s]._in * a[t]._out; return a[s]._out * a[t]._in + a[s]._in * a[t]._out;
}, },
neighbors = function(sID) {
var outbound = _.keys(matrix[sID] || {}),
inbound = _.keys(backwardMatrix[sID] || {});
return _.union(outbound, inbound);
},
makeInitialDQ = function() { makeInitialDQ = function() {
dQ = {}; dQ = {};
_.each(nodes, function(n1) { _.each(matrix, function(tars, s) {
var s = n1._id; var bw = backwardMatrix[s] || {},
_.each(nodes, function(n2) { keys = neighbors(s);
var t = n2._id, _.each(keys, function(t) {
ast = 0, var ast = (tars[t] || 0),
value; value;
if (t <= s) { ast += (bw[t] || 0);
return;
}
if (matrix[s] && matrix[s][t]) {
ast += matrix[s][t];
}
if (matrix[t] && matrix[t][s]) {
ast += matrix[t][s];
}
if (ast === 0) {
return;
}
value = ast * revM - notConnectedPenalty(s, t); value = ast * revM - notConnectedPenalty(s, t);
if (value > 0) { if (value > 0) {
setDQVal(s, t, value); setDQVal(s, t, value);
@ -231,61 +206,12 @@ function ModularityJoiner(nodes, edges) {
}); });
}, },
makeInitialHeap = function() { makeInitialHeap = function() {
heap = {}; heap = {};
_.each(dQ, setHeapToMaxInList); _.each(dQ, setHeapToMaxInList);
return heap; return heap;
}, },
updateDQAndHeapBKP = function (low, high) {
_.each(dQ, function (list, s) {
if (s < low) {
list[low] += list[high];
delete list[high];
if (heap[s] === low || heap[s] === high) {
setHeapToMaxInList(list, s);
} else {
if (dQ[s][heap[s]] < list[low]) {
heap[s] = low;
}
}
return;
}
if (s === low) {
delete list[high];
if (_.isEmpty(list)) {
delete dQ[s];
delete heap[s];
return;
}
_.each(list, function(v, k) {
if (k < high) {
list[k] += dQ[k][high];
delete dQ[k][high];
return;
}
if (high < k) {
list[k] += dQ[high][k];
return;
}
return;
});
setHeapToMaxInList(list, s);
return;
}
if (_.isEmpty(list)) {
delete dQ[s];
delete heap[s];
}
return;
});
delete dQ[high];
delete heap[high];
},
// i < j && i != j != k // i < j && i != j != k
updateDQAndHeapValue = function (i, j, k) { updateDQAndHeapValue = function (i, j, k) {
var val; var val;
@ -335,8 +261,6 @@ function ModularityJoiner(nodes, edges) {
}); });
}, },
//////////////////////////////////// ////////////////////////////////////
// getters // // getters //
//////////////////////////////////// ////////////////////////////////////
@ -430,21 +354,6 @@ function ModularityJoiner(nodes, edges) {
// Evaluate value of community by distance // // Evaluate value of community by distance //
////////////////////////////////////////////// //////////////////////////////////////////////
neighbors = function(sID) {
var neigh = [];
_.each(edges, function(e) {
if (e.source._id === sID) {
neigh.push(e.target._id);
return;
}
if (e.target._id === sID) {
neigh.push(e.source._id);
return;
}
});
return neigh;
},
floatDistStep = function(dist, depth, todo) { floatDistStep = function(dist, depth, todo) {
if (todo.length === 0) { if (todo.length === 0) {
return true; return true;
@ -462,7 +371,7 @@ function ModularityJoiner(nodes, edges) {
floatDist = function(sID) { floatDist = function(sID) {
var dist = {}; var dist = {};
_.each(_.pluck(nodes, "_id"), function(n) { _.each(matrix, function(u, n) {
dist[n] = Number.POSITIVE_INFINITY; dist[n] = Number.POSITIVE_INFINITY;
}); });
dist[sID] = 0; dist[sID] = 0;
@ -500,10 +409,6 @@ function ModularityJoiner(nodes, edges) {
} }
return val; return val;
}; };
if (nodes.length === 0 || edges.length === 0) {
isRunning = false;
throw "Load some nodes first.";
}
setup(); setup();
best = getBest(); best = getBest();
while (best !== null) { while (best !== null) {

View File

@ -63,21 +63,15 @@
describe('setup process', function() { describe('setup process', function() {
it('should throw an error if no nodes are given', function() {
expect(function() {
var s = new ModularityJoiner();
}).toThrow("Nodes have to be given.");
});
it('should throw an error if no edges are given', function() { it('should throw an error if no edges are given', function() {
expect(function() { expect(function() {
var s = new ModularityJoiner([]); var s = new ModularityJoiner();
}).toThrow("Edges have to be given."); }).toThrow("Edges have to be given.");
}); });
it('should not throw an error if mandatory information is given', function() { it('should not throw an error if mandatory information is given', function() {
expect(function() { expect(function() {
var s = new ModularityJoiner([], []); var s = new ModularityJoiner([]);
}).not.toThrow(); }).not.toThrow();
}); });
@ -104,7 +98,7 @@
} }
}, },
w = new WebWorkerWrapper(ModularityJoiner, cb, n, e); w = new WebWorkerWrapper(ModularityJoiner, cb, e);
}); });
waitsFor(function() { waitsFor(function() {
@ -129,7 +123,7 @@
beforeEach(function () { beforeEach(function () {
nodes = []; nodes = [];
edges = []; edges = [];
joiner = new ModularityJoiner(nodes, edges); joiner = new ModularityJoiner(edges);
testNetFour = function() { testNetFour = function() {
helper.insertSimpleNodes(nodes, ["0", "1", "2", "3"]); helper.insertSimpleNodes(nodes, ["0", "1", "2", "3"]);
edges.push(helper.createSimpleEdge(nodes, 0, 1)); edges.push(helper.createSimpleEdge(nodes, 0, 1));
@ -685,7 +679,7 @@
}); });
*/ */
}); });
/*
describe('checking the zachary karate club', function() { describe('checking the zachary karate club', function() {
beforeEach(function() { beforeEach(function() {
@ -819,18 +813,17 @@
}); });
it('should be able to find communities', function() { it('should be able to find communities', function() {
/* /////////////////////////////////////////////////////
correct acc to: NMCM09 /// correct acc to: NMCM09 //
Red: /// Red: //
21,23,24,19,27,16,30,33,34,29,15,9,31 /// 21,23,24,19,27,16,30,33,34,29,15,9,31 //
White: /// White: //
25, 26, 28, 32 /// 25, 26, 28, 32 //
Green: /// Green: //
5, 6, 7, 11, 17 /// 5, 6, 7, 11, 17 //
Blue: /// Blue: //
1, 2, 3, 4, 10, 14, 20, 22, 18, 13, 12 /// 1, 2, 3, 4, 10, 14, 20, 22, 18, 13, 12 //
*/ /////////////////////////////////////////////////////
this.addMatchers({ this.addMatchers({
toContainKarateClubCommunities: function() { toContainKarateClubCommunities: function() {
@ -893,7 +886,7 @@
}); });
}); });
*/
describe('checking consistency after join', function() { describe('checking consistency after join', function() {
beforeEach(function() { beforeEach(function() {
@ -1085,17 +1078,17 @@
// This is the max. number of nodes for the admin UI // This is the max. number of nodes for the admin UI
// However the format is realy unlikely in the adminUI // However the format is realy unlikely in the adminUI
/*
it('should be able to handle 3000 nodes', function() { it('should be able to handle 3000 nodes', function() {
var start = (new Date()).getTime(); var start = (new Date()).getTime(),
var i, best, nodeCount = 3000; i, best, nodeCount = 3000, diff;
helper.insertNSimpleNodes(nodes, nodeCount); helper.insertNSimpleNodes(nodes, nodeCount);
helper.insertClique(nodes, edges, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); helper.insertClique(nodes, edges, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
for (i = 11; i < nodeCount; i++) { for (i = 11; i < nodeCount; i++) {
edges.push(helper.createSimpleEdge(nodes, i - 1, i)); edges.push(helper.createSimpleEdge(nodes, i - 1, i));
edges.push(helper.createSimpleEdge(nodes, i, i - 2)); edges.push(helper.createSimpleEdge(nodes, i, i - 2));
} }
var diff = (new Date()).getTime() - start; diff = (new Date()).getTime() - start;
console.log("Runtime Fill:", diff, "ms"); console.log("Runtime Fill:", diff, "ms");
start = (new Date()).getTime(); start = (new Date()).getTime();
joiner.setup(); joiner.setup();
@ -1103,17 +1096,15 @@
console.log("Runtime Setup:", diff, "ms"); console.log("Runtime Setup:", diff, "ms");
start = (new Date()).getTime(); start = (new Date()).getTime();
best = joiner.getBest(); best = joiner.getBest();
var step = 0;
while (best !== null) { while (best !== null) {
joiner.joinCommunity(best); joiner.joinCommunity(best);
best = joiner.getBest(); best = joiner.getBest();
step++;
} }
diff = (new Date()).getTime() - start; diff = (new Date()).getTime() - start;
console.log("Runtime Compute:", diff, "ms"); console.log("Runtime Compute:", diff, "ms");
}); });
*/
// This is what we expect in the Admin UI // This is what we expect in the Admin UI
it('should be able to handle few large satelites', function() { it('should be able to handle few large satelites', function() {
var start = (new Date()).getTime(), var start = (new Date()).getTime(),
@ -1603,6 +1594,8 @@
}); });
});
/* /*
it('should be able to handle 10000 nodes', function() { it('should be able to handle 10000 nodes', function() {
@ -1634,8 +1627,6 @@
*/ */
}); });
});
/* /*
describe('configured as a worker', function() { describe('configured as a worker', function() {