1
0
Fork 0

Merge branch 'devel' of https://github.com/triAGENS/ArangoDB into devel

This commit is contained in:
Jan Steemann 2013-07-05 11:41:55 +02:00
commit 701f087e8f
2 changed files with 1778 additions and 62 deletions

View File

@ -1,5 +1,7 @@
/*jslint indent: 2, nomen: true, maxlen: 100, white: true plusplus: true */
/*global $, d3, _, console, alert, ModularityJoiner*/
/*global _*/
// Will be injected by WebWorkers
/*global self*/
////////////////////////////////////////////////////////////////////////////////
/// @brief Graph functionality
///
@ -29,6 +31,11 @@
function NodeReducer(nodes, edges) {
"use strict";
// We are executed as a worker
if (this.importScripts) {
this.importScripts("js/lib/underscore.js");
}
if (nodes === undefined) {
throw "Nodes have to be given.";
@ -36,10 +43,238 @@ function NodeReducer(nodes, edges) {
if (edges === undefined) {
throw "Edges have to be given.";
}
var self = this,
var
matrix = null,
m = 0,
revM = 0,
a = null,
dQ = null,
heap = null,
comms = {},
isRunning = false,
joiner = new ModularityJoiner(nodes, edges),
////////////////////////////////////
// Private functions //
////////////////////////////////////
/////////////////////////////////////
// Functions for Modularity Join //
/////////////////////////////////////
setHeapToMax = function(id) {
var maxT,
maxV = Number.NEGATIVE_INFINITY;
_.each(dQ[id], function(v, t) {
if (maxV < v) {
maxV = v;
maxT = t;
}
});
if (maxV < 0) {
delete heap[id];
return;
}
heap[id] = maxT;
},
setHeapToMaxInList = function(l, id) {
setHeapToMax(id);
},
isSetDQVal = function(i, j) {
if (i < j) {
return dQ[i] && dQ[i][j];
}
return dQ[j] && dQ[j][i];
},
// This does not check if everything exists,
// do it before!
getDQVal = function(i, j) {
if (i < j) {
return dQ[i][j];
}
return dQ[j][i];
},
setDQVal = function(i, j, v) {
if (i < j) {
dQ[i] = dQ[i] || {};
dQ[i][j] = v;
return;
}
dQ[j] = dQ[j] || {};
dQ[j][i] = v;
},
delDQVal = function(i, j) {
if (i < j) {
if (!dQ[i]) {
return;
}
delete dQ[i][j];
if (_.isEmpty(dQ[i])) {
delete dQ[i];
}
return;
}
if (i === j) {
return;
}
delDQVal(j, i);
},
updateHeap = function(i, j) {
var hv, val;
if (i < j) {
if (!isSetDQVal(i, j)) {
setHeapToMax(i);
return;
}
val = getDQVal(i, j);
if (heap[i] === j) {
setHeapToMax(i);
return;
}
if (!isSetDQVal(i, heap[i])) {
setHeapToMax(i);
return;
}
hv = getDQVal(i, heap[i]);
if (hv < val) {
heap[i] = j;
}
return;
}
if (i === j) {
return;
}
updateHeap(j, i);
},
updateDegrees = function(low, high) {
a[low]._in += a[high]._in;
a[low]._out += a[high]._out;
delete a[high];
},
makeAdjacencyMatrix = function() {
matrix = {};
_.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;
});
m = edges.length;
revM = 1/m;
return matrix;
},
makeInitialDegrees = function() {
a = {};
_.each(nodes, function (n) {
a[n._id] = {
_in: n._inboundCounter / m,
_out: n._outboundCounter / m
};
});
return a;
},
notConnectedPenalty = function(s, t) {
return a[s]._out * a[t]._in + a[s]._in * a[t]._out;
},
makeInitialDQ = function() {
dQ = {};
_.each(nodes, function(n1) {
var s = n1._id;
_.each(nodes, function(n2) {
var t = n2._id,
ast = 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;
}
value = ast * revM - notConnectedPenalty(s, t);
if (value > 0) {
setDQVal(s, t, value);
}
return;
});
});
},
makeInitialHeap = function() {
heap = {};
_.each(dQ, setHeapToMaxInList);
return heap;
},
// i < j && i != j != k
updateDQAndHeapValue = function (i, j, k) {
var val;
if (isSetDQVal(k, i)) {
val = getDQVal(k, i);
if (isSetDQVal(k, j)) {
val += getDQVal(k, j);
setDQVal(k, i, val);
delDQVal(k, j);
updateHeap(k, i);
updateHeap(k, j);
return;
}
val -= notConnectedPenalty(k, j);
if (val < 0) {
delDQVal(k, i);
}
updateHeap(k, i);
return;
}
if (isSetDQVal(k, j)) {
val = getDQVal(k, j);
val -= notConnectedPenalty(k, i);
if (val > 0) {
setDQVal(k, i, val);
}
updateHeap(k, i);
delDQVal(k, j);
updateHeap(k, j);
}
},
updateDQAndHeap = function (low, high) {
_.each(dQ, function (list, s) {
if (s === low || s === high) {
_.each(list, function(v, t) {
if (t === high) {
delDQVal(low, high);
updateHeap(low, high);
return;
}
updateDQAndHeapValue(low, high, t);
});
return;
}
updateDQAndHeapValue(low, high, s);
});
},
/////////////////////////////
// Functions for Buckets //
/////////////////////////////
neighbors = function(sID) {
var neigh = [];
@ -89,40 +324,6 @@ function NodeReducer(nodes, edges) {
};
},
/*
dijkstra = function(sID) {
var dist = {},
leftOvers, next, neigh,
filterNotNext = function(e) {
return e !== next;
},
computeNeighbours = function(v) {
if (_.contains(leftOvers, v)) {
if (dist[v] > dist[next] + 1) {
dist[v] = dist[next] + 1;
}
}
};
leftOvers = _.pluck(nodes, "_id");
_.each(leftOvers, function(n) {
dist[n] = Number.POSITIVE_INFINITY;
});
dist[sID] = 0;
while(leftOvers.length > 0) {
next = _.min(leftOvers, minDist(dist));
if (next === Number.POSITIVE_INFINITY) {
break;
}
leftOvers = leftOvers.filter(filterNotNext);
neigh = neighbors(next);
_.each(neigh, computeNeighbours);
}
return dist;
},
*/
addNode = function(bucket, node) {
bucket.push(node);
},
@ -147,9 +348,106 @@ function NodeReducer(nodes, edges) {
propCount++;
countMatch++;
return countMatch / propCount;
};
},
self.getCommunity = function(limit, focus) {
////////////////////////////////////
// getters //
////////////////////////////////////
getAdjacencyMatrix = function() {
return matrix;
},
getHeap = function() {
return heap;
},
getDQ = function() {
return dQ;
},
getDegrees = function() {
return a;
},
getCommunities = function() {
return comms;
},
getBestCommunity = function (communities) {
var bestQ = Number.NEGATIVE_INFINITY,
bestC;
_.each(communities, function (obj) {
if (obj.q > bestQ) {
bestQ = obj.q;
bestC = obj.nodes;
}
});
return bestC;
},
getBest = function() {
var bestL, bestS, bestV = Number.NEGATIVE_INFINITY;
_.each(heap, function(lID, sID) {
if (bestV < dQ[sID][lID]) {
bestL = lID;
bestS = sID;
bestV = dQ[sID][lID];
}
});
if (bestV <= 0) {
return null;
}
return {
sID: bestS,
lID: bestL,
val: bestV
};
},
////////////////////////////////////
// setup //
////////////////////////////////////
setup = function() {
makeAdjacencyMatrix();
makeInitialDegrees();
makeInitialDQ();
makeInitialHeap();
comms = {};
},
////////////////////////////////////
// computation //
////////////////////////////////////
joinCommunity = function(comm) {
var s = comm.sID,
l = comm.lID,
q = comm.val;
comms[s] = comms[s] || {nodes: [s], q: 0};
if (comms[l]) {
comms[s].nodes = comms[s].nodes.concat(comms[l].nodes);
comms[s].q += comms[l].q;
delete comms[l];
} else {
comms[s].nodes.push(l);
}
comms[s].q += q;
updateDQAndHeap(s, l);
updateDegrees(s, l);
},
////////////////////////////////////
// Get only the Best Community //
////////////////////////////////////
getCommunity = function(limit, focus) {
if (isRunning) {
throw "Still running.";
}
@ -158,17 +456,6 @@ function NodeReducer(nodes, edges) {
res = [],
dist = {},
best,
getBest = function (communities) {
var bestQ = Number.NEGATIVE_INFINITY,
bestC;
_.each(communities, function (obj) {
if (obj.q > bestQ) {
bestQ = obj.q;
bestC = obj.nodes;
}
});
return bestC;
},
sortByDistance = function (a, b) {
var d1 = dist[_.min(a,minDist(dist))],
d2 = dist[_.min(b,minDist(dist))],
@ -182,13 +469,13 @@ function NodeReducer(nodes, edges) {
isRunning = false;
throw "Load some nodes first.";
}
joiner.setup();
best = joiner.getBest();
setup();
best = getBest();
while (best !== null) {
joiner.joinCommunity(best);
best = joiner.getBest();
joinCommunity(best);
best = getBest();
}
coms = joiner.getCommunities();
coms = getCommunities();
if (focus !== undefined) {
_.each(coms, function(obj, key) {
@ -204,10 +491,10 @@ function NodeReducer(nodes, edges) {
return res[0];
}
isRunning = false;
return getBest(coms);
};
return getBestCommunity(coms);
},
self.bucketNodes = function(toSort, numBuckets) {
bucketNodes = function(toSort, numBuckets) {
var res = [],
threshold = 0.5;
if (toSort.length <= numBuckets) {
@ -236,4 +523,28 @@ function NodeReducer(nodes, edges) {
return res;
};
////////////////////////////////////
// Public functions //
////////////////////////////////////
this.getAdjacencyMatrix = getAdjacencyMatrix;
this.getHeap = getHeap;
this.getDQ = getDQ;
this.getDegrees = getDegrees;
this.getCommunities = getCommunities;
this.getBest = getBest;
this.setup = setup;
this.joinCommunity = joinCommunity;
this.getCommunity = getCommunity;
this.bucketNodes = bucketNodes;
}