mirror of https://gitee.com/bigwinds/arangodb
GraphViewer: CommunityDetection algorithm implemented successfully, however distance is not yet considered for decission
This commit is contained in:
parent
3d1bd8dfde
commit
6d65938645
|
@ -70,17 +70,136 @@ function NodeReducer(nodes, edges) {
|
||||||
dQ[sID][lID] = cFact - a[sID] * a[lID];
|
dQ[sID][lID] = cFact - a[sID] * a[lID];
|
||||||
if (heap[sID].val < dQ[sID][lID]) {
|
if (heap[sID].val < dQ[sID][lID]) {
|
||||||
heap[sID].val = dQ[sID][lID];
|
heap[sID].val = dQ[sID][lID];
|
||||||
|
heap[sID].sID = sID;
|
||||||
heap[sID].lID = lID;
|
heap[sID].lID = lID;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getLargestOnHeap = function(heap) {
|
||||||
|
return _.max(heap, function(e) {
|
||||||
|
return e.val;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
joinCommunities = function(sID, lID, coms) {
|
||||||
|
var old = coms[sID] || [sID],
|
||||||
|
newC = coms[lID] || [lID];
|
||||||
|
coms[lID] = old.concat(newC);
|
||||||
|
delete coms[sID];
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
getDQValue = function(dQ, a, b) {
|
||||||
|
if (a < b) {
|
||||||
|
if (dQ[a] !== undefined) {
|
||||||
|
return dQ[a][b];
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (dQ[b] !== undefined) {
|
||||||
|
return dQ[b][a];
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
|
||||||
|
setDQValue = function(dQ, heap, a, b, val) {
|
||||||
|
if (a < b) {
|
||||||
|
if(dQ[a] === undefined) {
|
||||||
|
dQ[a] = {};
|
||||||
|
heap[a] = {};
|
||||||
|
heap[a].val = -1;
|
||||||
|
}
|
||||||
|
dQ[a][b] = val;
|
||||||
|
if (heap[a].val < val) {
|
||||||
|
heap[a].val = val;
|
||||||
|
heap[a].sID = a;
|
||||||
|
heap[a].lID = b;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(dQ[b] === undefined) {
|
||||||
|
dQ[b] = {};
|
||||||
|
heap[b] = {};
|
||||||
|
heap[b].val = -1;
|
||||||
|
}
|
||||||
|
dQ[b][a] = val;
|
||||||
|
if (heap[b].val < val) {
|
||||||
|
heap[b].val = val;
|
||||||
|
heap[b].sID = b;
|
||||||
|
heap[b].lID = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
delDQValue = function(dQ, a, b) {
|
||||||
|
if (a < b) {
|
||||||
|
delete dQ[a][b];
|
||||||
|
} else {
|
||||||
|
delete dQ[b][a];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
updateValues = function(largest, dQ, a, heap) {
|
||||||
|
var lID = largest.lID,
|
||||||
|
sID = largest.sID;
|
||||||
|
_.each(nodes, function (n) {
|
||||||
|
var id = n._id;
|
||||||
|
if (id == sID || id == lID) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var c1 = getDQValue(dQ, id, sID),
|
||||||
|
c2 = getDQValue(dQ, id, lID);
|
||||||
|
if (c1 !== undefined) {
|
||||||
|
if (c2 !== undefined) {
|
||||||
|
setDQValue(dQ, heap, id, lID, c1 + c2);
|
||||||
|
} else {
|
||||||
|
setDQValue(dQ, heap, id, lID, c1 - 2 * a[lID] * a[id]);
|
||||||
|
}
|
||||||
|
delDQValue(dQ, id, sID);
|
||||||
|
} else {
|
||||||
|
if (c2 !== undefined) {
|
||||||
|
setDQValue(dQ, heap, id, lID, c2- 2 * a[sID] * a[id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
delete dQ[sID];
|
||||||
|
delete heap[sID];
|
||||||
|
a[lID] += a[sID];
|
||||||
|
delete a[sID];
|
||||||
|
},
|
||||||
|
|
||||||
|
communityDetectionStep = function(dQ, a, heap, coms) {
|
||||||
|
var l = getLargestOnHeap(heap);
|
||||||
|
if (l.val < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
joinCommunities(l.sID, l.lID, coms);
|
||||||
|
updateValues(l, dQ, a, heap);
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self.getCommunity = function(limit, focus) {
|
self.getCommunity = function(limit, focus) {
|
||||||
var dQ = {},
|
var dQ = {},
|
||||||
a = {},
|
a = {},
|
||||||
heap = {};
|
heap = {},
|
||||||
|
q = 0,
|
||||||
|
coms = {},
|
||||||
|
res = [];
|
||||||
|
if (nodes.length === 0 || edges.length === 0) {
|
||||||
|
throw "Load some nodes first.";
|
||||||
|
}
|
||||||
populateValues(dQ, a, heap);
|
populateValues(dQ, a, heap);
|
||||||
|
while (communityDetectionStep(dQ, a, heap, coms)) {
|
||||||
return [];
|
}
|
||||||
|
res = _.values(coms);
|
||||||
|
res.sort(function(a, b) {
|
||||||
|
return b.length - a.length;
|
||||||
|
});
|
||||||
|
if (_.contains(res[0], focus)) {
|
||||||
|
return res[1];
|
||||||
|
}
|
||||||
|
return res[0];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,14 +73,13 @@ var helper = helper || {};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
helper.createClique = function(nodes, toConnect) {
|
helper.insertClique = function(nodes, edges, toConnect) {
|
||||||
var edges = [], i, j;
|
var i, j;
|
||||||
for (i = 0; i < toConnect.length - 1; i++) {
|
for (i = 0; i < toConnect.length - 1; i++) {
|
||||||
for (j = i + 1; j < toConnect.length; j++) {
|
for (j = i + 1; j < toConnect.length; j++) {
|
||||||
edges.push(helper.createSimpleEdge(nodes, toConnect[i], toConnect[j]));
|
edges.push(helper.createSimpleEdge(nodes, toConnect[i], toConnect[j]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return edges;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}());
|
}());
|
|
@ -75,16 +75,13 @@
|
||||||
var com = this.actual,
|
var com = this.actual,
|
||||||
check = true;
|
check = true;
|
||||||
this.message = function() {
|
this.message = function() {
|
||||||
var msg = _.map(com, function(c) {
|
return "Expected " + com + " to contain " + ns;
|
||||||
return c._id;
|
|
||||||
});
|
|
||||||
return "Expected " + msg + " to contain " + ns;
|
|
||||||
};
|
};
|
||||||
if (com.length !== ns.length) {
|
if (com.length !== ns.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_.each(ns, function(n) {
|
_.each(ns, function(n) {
|
||||||
if(!_.contains(com, nodes[n])) {
|
if(!_.contains(com, n)) {
|
||||||
check = false;
|
check = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -112,13 +109,13 @@
|
||||||
edges.push(helper.createSimpleEdge(nodes, 0, 3));
|
edges.push(helper.createSimpleEdge(nodes, 0, 3));
|
||||||
edges.push(helper.createSimpleEdge(nodes, 3, 4));
|
edges.push(helper.createSimpleEdge(nodes, 3, 4));
|
||||||
|
|
||||||
var com = reducer.getCommunity(2, nodes[4]);
|
var com = reducer.getCommunity(3, nodes[4]);
|
||||||
expect(com).toContainNodes([0, 1, 2, 3]);
|
expect(com).toContainNodes([0, 1, 2]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should prefer cliques as a community over an equal sized other group', function() {
|
it('should prefer cliques as a community over an equal sized other group', function() {
|
||||||
nodes = helper.createSimpleNodes([0, 1, 2, 3, 4, 5, 6, 7, 8]);
|
helper.insertSimpleNodes(nodes, [0, 1, 2, 3, 4, 5, 6, 7, 8]);
|
||||||
edges = helper.createClique(nodes, [0, 1, 2, 3]);
|
helper.insertClique(nodes, edges, [0, 1, 2, 3]);
|
||||||
edges.push(helper.createSimpleEdge(nodes, 4, 3));
|
edges.push(helper.createSimpleEdge(nodes, 4, 3));
|
||||||
edges.push(helper.createSimpleEdge(nodes, 4, 5));
|
edges.push(helper.createSimpleEdge(nodes, 4, 5));
|
||||||
edges.push(helper.createSimpleEdge(nodes, 5, 6));
|
edges.push(helper.createSimpleEdge(nodes, 5, 6));
|
||||||
|
@ -130,8 +127,8 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not return a close group if there is an alternative', function() {
|
it('should not return a close group if there is an alternative', function() {
|
||||||
nodes = helper.createSimpleNodes([0, 1, 2, 3, 4, 5, 6, 7]);
|
helper.insertSimpleNodes(nodes, [0, 1, 2, 3, 4, 5, 6, 7]);
|
||||||
edges = helper.createClique(nodes, [0, 1, 2]);
|
helper.insertClique(nodes, edges, [0, 1, 2]);
|
||||||
edges.push(helper.createSimpleEdge(nodes, 3, 2));
|
edges.push(helper.createSimpleEdge(nodes, 3, 2));
|
||||||
edges.push(helper.createSimpleEdge(nodes, 3, 4));
|
edges.push(helper.createSimpleEdge(nodes, 3, 4));
|
||||||
edges.push(helper.createSimpleEdge(nodes, 4, 5));
|
edges.push(helper.createSimpleEdge(nodes, 4, 5));
|
||||||
|
|
Loading…
Reference in New Issue