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
|
/// @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) {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue