mirror of https://gitee.com/bigwinds/arangodb
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:
parent
2b7bb78fa6
commit
2d16ac415e
|
@ -27,17 +27,16 @@
|
|||
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function ModularityJoiner(nodes, edges) {
|
||||
function ModularityJoiner(edges) {
|
||||
"use strict";
|
||||
|
||||
if (nodes === undefined) {
|
||||
throw "Nodes have to be given.";
|
||||
}
|
||||
|
||||
if (edges === undefined) {
|
||||
throw "Edges have to be given.";
|
||||
}
|
||||
|
||||
var matrix = null,
|
||||
backwardMatrix,
|
||||
degrees = null,
|
||||
m = 0,
|
||||
revM = 0,
|
||||
a = null,
|
||||
|
@ -149,11 +148,19 @@ function ModularityJoiner(nodes, edges) {
|
|||
|
||||
makeAdjacencyMatrix = function() {
|
||||
matrix = {};
|
||||
backwardMatrix = {};
|
||||
degrees = {};
|
||||
_.each(edges, function (e) {
|
||||
var s = e.source._id,
|
||||
t = e.target._id;
|
||||
matrix[s] = matrix[s] || {};
|
||||
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;
|
||||
revM = 1/m;
|
||||
|
@ -162,76 +169,42 @@ function ModularityJoiner(nodes, edges) {
|
|||
|
||||
makeInitialDegrees = function() {
|
||||
a = {};
|
||||
_.each(nodes, function (n) {
|
||||
a[n._id] = {
|
||||
_in: n._inboundCounter / m,
|
||||
_out: n._outboundCounter / m
|
||||
_.each(degrees, function (n, id) {
|
||||
a[id] = {
|
||||
_in: n._in / m,
|
||||
_out: n._out / m
|
||||
};
|
||||
});
|
||||
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) {
|
||||
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() {
|
||||
dQ = {};
|
||||
_.each(nodes, function(n1) {
|
||||
var s = n1._id;
|
||||
_.each(nodes, function(n2) {
|
||||
var t = n2._id,
|
||||
ast = 0,
|
||||
_.each(matrix, function(tars, s) {
|
||||
var bw = backwardMatrix[s] || {},
|
||||
keys = neighbors(s);
|
||||
_.each(keys, function(t) {
|
||||
var ast = (tars[t] || 0),
|
||||
value;
|
||||
if (t <= s) {
|
||||
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;
|
||||
}
|
||||
ast += (bw[t] || 0);
|
||||
value = ast * revM - notConnectedPenalty(s, t);
|
||||
if (value > 0) {
|
||||
setDQVal(s, t, value);
|
||||
}
|
||||
return;
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
makeInitialHeap = function() {
|
||||
heap = {};
|
||||
|
@ -239,53 +212,6 @@ function ModularityJoiner(nodes, edges) {
|
|||
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
|
||||
updateDQAndHeapValue = function (i, j, k) {
|
||||
var val;
|
||||
|
@ -335,8 +261,6 @@ function ModularityJoiner(nodes, edges) {
|
|||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////
|
||||
// getters //
|
||||
////////////////////////////////////
|
||||
|
@ -430,21 +354,6 @@ function ModularityJoiner(nodes, edges) {
|
|||
// 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) {
|
||||
if (todo.length === 0) {
|
||||
return true;
|
||||
|
@ -462,7 +371,7 @@ function ModularityJoiner(nodes, edges) {
|
|||
|
||||
floatDist = function(sID) {
|
||||
var dist = {};
|
||||
_.each(_.pluck(nodes, "_id"), function(n) {
|
||||
_.each(matrix, function(u, n) {
|
||||
dist[n] = Number.POSITIVE_INFINITY;
|
||||
});
|
||||
dist[sID] = 0;
|
||||
|
@ -500,10 +409,6 @@ function ModularityJoiner(nodes, edges) {
|
|||
}
|
||||
return val;
|
||||
};
|
||||
if (nodes.length === 0 || edges.length === 0) {
|
||||
isRunning = false;
|
||||
throw "Load some nodes first.";
|
||||
}
|
||||
setup();
|
||||
best = getBest();
|
||||
while (best !== null) {
|
||||
|
|
|
@ -63,21 +63,15 @@
|
|||
|
||||
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() {
|
||||
expect(function() {
|
||||
var s = new ModularityJoiner([]);
|
||||
var s = new ModularityJoiner();
|
||||
}).toThrow("Edges have to be given.");
|
||||
});
|
||||
|
||||
it('should not throw an error if mandatory information is given', function() {
|
||||
expect(function() {
|
||||
var s = new ModularityJoiner([], []);
|
||||
var s = new ModularityJoiner([]);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
|
@ -104,7 +98,7 @@
|
|||
}
|
||||
|
||||
},
|
||||
w = new WebWorkerWrapper(ModularityJoiner, cb, n, e);
|
||||
w = new WebWorkerWrapper(ModularityJoiner, cb, e);
|
||||
});
|
||||
|
||||
waitsFor(function() {
|
||||
|
@ -129,7 +123,7 @@
|
|||
beforeEach(function () {
|
||||
nodes = [];
|
||||
edges = [];
|
||||
joiner = new ModularityJoiner(nodes, edges);
|
||||
joiner = new ModularityJoiner(edges);
|
||||
testNetFour = function() {
|
||||
helper.insertSimpleNodes(nodes, ["0", "1", "2", "3"]);
|
||||
edges.push(helper.createSimpleEdge(nodes, 0, 1));
|
||||
|
@ -685,7 +679,7 @@
|
|||
});
|
||||
*/
|
||||
});
|
||||
|
||||
/*
|
||||
describe('checking the zachary karate club', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
|
@ -819,19 +813,18 @@
|
|||
});
|
||||
|
||||
it('should be able to find communities', function() {
|
||||
/*
|
||||
correct acc to: NMCM09
|
||||
Red:
|
||||
21,23,24,19,27,16,30,33,34,29,15,9,31
|
||||
White:
|
||||
25, 26, 28, 32
|
||||
Green:
|
||||
5, 6, 7, 11, 17
|
||||
Blue:
|
||||
1, 2, 3, 4, 10, 14, 20, 22, 18, 13, 12
|
||||
*/
|
||||
/////////////////////////////////////////////////////
|
||||
/// correct acc to: NMCM09 //
|
||||
/// Red: //
|
||||
/// 21,23,24,19,27,16,30,33,34,29,15,9,31 //
|
||||
/// White: //
|
||||
/// 25, 26, 28, 32 //
|
||||
/// Green: //
|
||||
/// 5, 6, 7, 11, 17 //
|
||||
/// Blue: //
|
||||
/// 1, 2, 3, 4, 10, 14, 20, 22, 18, 13, 12 //
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
|
||||
this.addMatchers({
|
||||
toContainKarateClubCommunities: function() {
|
||||
var c1 = [
|
||||
|
@ -893,7 +886,7 @@
|
|||
});
|
||||
|
||||
});
|
||||
|
||||
*/
|
||||
describe('checking consistency after join', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
|
@ -1085,17 +1078,17 @@
|
|||
|
||||
// This is the max. number of nodes for the admin UI
|
||||
// However the format is realy unlikely in the adminUI
|
||||
/*
|
||||
|
||||
it('should be able to handle 3000 nodes', function() {
|
||||
var start = (new Date()).getTime();
|
||||
var i, best, nodeCount = 3000;
|
||||
var start = (new Date()).getTime(),
|
||||
i, best, nodeCount = 3000, diff;
|
||||
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;
|
||||
diff = (new Date()).getTime() - start;
|
||||
console.log("Runtime Fill:", diff, "ms");
|
||||
start = (new Date()).getTime();
|
||||
joiner.setup();
|
||||
|
@ -1103,17 +1096,15 @@
|
|||
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");
|
||||
});
|
||||
*/
|
||||
|
||||
// This is what we expect in the Admin UI
|
||||
it('should be able to handle few large satelites', function() {
|
||||
var start = (new Date()).getTime(),
|
||||
|
@ -1603,37 +1594,37 @@
|
|||
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
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");
|
||||
});
|
||||
*/
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
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");
|
||||
});
|
||||
*/
|
||||
});
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue