StackGenVis: Alignment of Data, Algorithms, and Models for Stacking Ensemble Learning Using Performance Metrics
https://doi.org/10.1109/TVCG.2020.3030352
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
3.7 KiB
156 lines
3.7 KiB
var tarjan = require('strongly-connected-components');
|
|
|
|
module.exports = function findCircuits(edges, cb) {
|
|
var circuits = []; // Output
|
|
|
|
var stack = [];
|
|
var blocked = [];
|
|
var B = {};
|
|
var Ak = [];
|
|
var s;
|
|
|
|
function unblock(u) {
|
|
blocked[u] = false;
|
|
if(B.hasOwnProperty(u)) {
|
|
Object.keys(B[u]).forEach(function(w) {
|
|
delete B[u][w];
|
|
if(blocked[w]) {unblock(w);}
|
|
});
|
|
}
|
|
}
|
|
|
|
function circuit(v) {
|
|
var found = false;
|
|
|
|
stack.push(v);
|
|
blocked[v] = true;
|
|
|
|
// L1
|
|
var i;
|
|
var w;
|
|
for(i = 0; i < Ak[v].length; i++) {
|
|
w = Ak[v][i];
|
|
if(w === s) {
|
|
output(s, stack);
|
|
found = true;
|
|
} else if(!blocked[w]) {
|
|
found = circuit(w);
|
|
}
|
|
}
|
|
|
|
// L2
|
|
if(found) {
|
|
unblock(v);
|
|
} else {
|
|
for(i = 0; i < Ak[v].length; i++) {
|
|
w = Ak[v][i];
|
|
var entry = B[w];
|
|
|
|
if(!entry) {
|
|
entry = {};
|
|
B[w] = entry;
|
|
}
|
|
|
|
entry[w] = true;
|
|
}
|
|
}
|
|
stack.pop();
|
|
return found;
|
|
}
|
|
|
|
function output(start, stack) {
|
|
var cycle = [].concat(stack).concat(start);
|
|
if(cb) {
|
|
cb(circuit);
|
|
} else {
|
|
circuits.push(cycle);
|
|
}
|
|
}
|
|
|
|
function subgraph(minId) {
|
|
// Remove edges with indice smaller than minId
|
|
for(var i = 0; i < edges.length; i++) {
|
|
if(i < minId) edges[i] = [];
|
|
edges[i] = edges[i].filter(function(i) {
|
|
return i >= minId;
|
|
});
|
|
}
|
|
}
|
|
|
|
function adjacencyStructureSCC(from) {
|
|
// Make subgraph starting from vertex minId
|
|
subgraph(from);
|
|
var g = edges;
|
|
|
|
// Find strongly connected components using Tarjan algorithm
|
|
var sccs = tarjan(g);
|
|
|
|
// Filter out trivial connected components (ie. made of one node)
|
|
var ccs = sccs.components.filter(function(scc) {
|
|
return scc.length > 1;
|
|
});
|
|
|
|
// Find least vertex
|
|
var leastVertex = Infinity;
|
|
var leastVertexComponent;
|
|
for(var i = 0; i < ccs.length; i++) {
|
|
for(var j = 0; j < ccs[i].length; j++) {
|
|
if(ccs[i][j] < leastVertex) {
|
|
leastVertex = ccs[i][j];
|
|
leastVertexComponent = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
var cc = ccs[leastVertexComponent];
|
|
|
|
if(!cc) return false;
|
|
|
|
// Return the adjacency list of first component
|
|
var adjList = edges.map(function(l, index) {
|
|
if(cc.indexOf(index) === -1) return [];
|
|
return l.filter(function(i) {
|
|
return cc.indexOf(i) !== -1;
|
|
});
|
|
});
|
|
|
|
return {
|
|
leastVertex: leastVertex,
|
|
adjList: adjList
|
|
};
|
|
}
|
|
|
|
s = 0;
|
|
var n = edges.length;
|
|
while(s < n) {
|
|
// find strong component with least vertex in
|
|
// subgraph starting from vertex `s`
|
|
var p = adjacencyStructureSCC(s);
|
|
|
|
// Its least vertex
|
|
s = p.leastVertex;
|
|
// Its adjacency list
|
|
Ak = p.adjList;
|
|
|
|
if(Ak) {
|
|
for(var i = 0; i < Ak.length; i++) {
|
|
for(var j = 0; j < Ak[i].length; j++) {
|
|
var vertexId = Ak[i][j];
|
|
blocked[+vertexId] = false;
|
|
B[vertexId] = {};
|
|
}
|
|
}
|
|
circuit(s);
|
|
s = s + 1;
|
|
} else {
|
|
s = n;
|
|
}
|
|
|
|
}
|
|
|
|
if(cb) {
|
|
return;
|
|
} else {
|
|
return circuits;
|
|
}
|
|
};
|
|
|