Skip to content

Commit

Permalink
fix caused by Array.sort not sorting by number by default
Browse files Browse the repository at this point in the history
  • Loading branch information
jdfekete committed Apr 18, 2015
1 parent a496826 commit 592273a
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 178 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ reorder.v1.js: \
src/printmat.js \
src/mat2graph.js \
src/graph2mat.js \
src/count_crossings.js \
src/barycenter.js \
src/dijkstra.js \
src/dist.js \
Expand Down
85 changes: 43 additions & 42 deletions reorder.v1.js
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ reorder.graph = function(nodes, links, directed) {
}
}
if (ccomp.length) {
ccomp.sort();
ccomp.sort(function(a,b){ return a-b; });
comps.push(ccomp);
}
}
Expand Down Expand Up @@ -636,56 +636,24 @@ reorder.graph2mat = function(graph, directed) {
}
return mat;
};
reorder.barycenter = function(graph, iter, comps) {
var perm = [];
// Compute the barycenter heuristic on each connected component
if (! comps) {
comps = graph.components();
}
for (var i = 0; i < comps.length; i++)
perm = perm.concat(reorder.barycenter1(graph, comps[i], iter));
return perm;
};

// Take the list of neighbor indexes and return the median according to
// P. Eades and N. Wormald, Edge crossings in drawings of bipartite graphs.
// Algorithmica, vol. 11 (1994) 379–403.
function median(neighbors) {
if (neighbors.length == 0)
return -1; // should not happen
if (neighbors.length == 1)
return neighbors[0];
if (neighbors.length == 2)
return (neighbors[0]+neighbors[1])/2;
neighbors.sort();
if (neighbors.length % 2)
return neighbors[(neighbors.length-1)/2];
var rm = neighbors.length/2,
lm = rm - 1,
rspan = neighbors[neighbors.length-1] - neighbors[rm],
lspan = neighbors[lm] - neighbors[0];
if (lspan == rspan)
return (neighbors[lm] + neighbors[rm])/2;
else
return (neighbors[lm]*rspan + neighbors[rm]*lspan) / (lspan+rspan);
}

// Wilhelm Barth, Petra Mutzel, Michael Jünger:
// Simple and Efficient Bilayer Cross Counting.
// J. Graph Algorithms Appl. 8(2): 179-194 (2004)
function count_crossings(graph, north, south) {
var i, j, southPos = [], n,
var i, j, n,
firstIndex, treeSize, tree, index, weightSum,
invert = false, crosscount;

// Choose the smaller axis
if (north.length < south.length) {
var tmp = north;
north = south;
south = tmp;
invert = true;
}

var south_inv = inverse_permutation(south);
var south_inv = inverse_permutation(south),
southsequence = [];

for (i = 0; i < north.length; i++) {
if (invert) {
Expand All @@ -700,8 +668,8 @@ function count_crossings(graph, north, south) {
return south_inv[e.source.index];
});
}
n.sort();
southPos = southPos.concat(n);
n.sort(function(a,b){ return a-b; });
southsequence = southsequence.concat(n);
}

firstIndex = 1;
Expand All @@ -712,8 +680,8 @@ function count_crossings(graph, north, south) {
tree = science.zeroes(treeSize);

crosscount = 0;
for (i = 0; i < southPos.length; i++) {
index = southPos[i] + firstIndex;
for (i = 0; i < southsequence.length; i++) {
index = southsequence[i] + firstIndex;
tree[index]++;
while (index > 0) {
if (index%2) crosscount += tree[index+1];
Expand All @@ -724,6 +692,39 @@ function count_crossings(graph, north, south) {
return crosscount;
}
reorder.count_crossings = count_crossings;
reorder.barycenter = function(graph, iter, comps) {
var perm = [];
// Compute the barycenter heuristic on each connected component
if (! comps) {
comps = graph.components();
}
for (var i = 0; i < comps.length; i++)
perm = perm.concat(reorder.barycenter1(graph, comps[i], iter));
return perm;
};

// Take the list of neighbor indexes and return the median according to
// P. Eades and N. Wormald, Edge crossings in drawings of bipartite graphs.
// Algorithmica, vol. 11 (1994) 379–403.
function median(neighbors) {
if (neighbors.length == 0)
return -1; // should not happen
if (neighbors.length == 1)
return neighbors[0];
if (neighbors.length == 2)
return (neighbors[0]+neighbors[1])/2;
neighbors.sort(function(a,b){ return a-b; });
if (neighbors.length % 2)
return neighbors[(neighbors.length-1)/2];
var rm = neighbors.length/2,
lm = rm - 1,
rspan = neighbors[neighbors.length-1] - neighbors[rm],
lspan = neighbors[lm] - neighbors[0];
if (lspan == rspan)
return (neighbors[lm] + neighbors[rm])/2;
else
return (neighbors[lm]*rspan + neighbors[rm]*lspan) / (lspan+rspan);
}

reorder.barycenter1 = function(graph, comp, iter) {
var nodes = graph.nodes(),
Expand All @@ -735,7 +736,7 @@ reorder.barycenter1 = function(graph, comp, iter) {
return comp;

if (! iter)
iter = 10;
iter = 24;
else if ((iter%2)==1)
iter++; // want even number of iterations

Expand Down
2 changes: 1 addition & 1 deletion reorder.v1.min.js

Large diffs are not rendered by default.

57 changes: 1 addition & 56 deletions src/barycenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function median(neighbors) {
return neighbors[0];
if (neighbors.length == 2)
return (neighbors[0]+neighbors[1])/2;
neighbors.sort();
neighbors.sort(function(a,b){ return a-b; });
if (neighbors.length % 2)
return neighbors[(neighbors.length-1)/2];
var rm = neighbors.length/2,
Expand All @@ -32,61 +32,6 @@ function median(neighbors) {
return (neighbors[lm]*rspan + neighbors[rm]*lspan) / (lspan+rspan);
}

// Wilhelm Barth, Petra Mutzel, Michael Jünger:
// Simple and Efficient Bilayer Cross Counting.
// J. Graph Algorithms Appl. 8(2): 179-194 (2004)
function count_crossings(graph, north, south) {
var i, j, southPos = [], n,
firstIndex, treeSize, tree, index, weightSum,
invert = false, crosscount;

if (north.length < south.length) {
var tmp = north;
north = south;
south = tmp;
invert = true;
}

var south_inv = inverse_permutation(south);

for (i = 0; i < north.length; i++) {
if (invert) {
n = graph.inEdges(north[i])
.map(function(e) {
return south_inv[e.target.index];
});
}
else {
n = graph.outEdges(north[i])
.map(function(e) {
return south_inv[e.source.index];
});
}
n.sort();
southPos = southPos.concat(n);
}

firstIndex = 1;
while (firstIndex < south.length)
firstIndex <<= 1;
treeSize = 2 * firstIndex - 1;
firstIndex -= 1;
tree = science.zeroes(treeSize);

crosscount = 0;
for (i = 0; i < southPos.length; i++) {
index = southPos[i] + firstIndex;
tree[index]++;
while (index > 0) {
if (index%2) crosscount += tree[index+1];
index = (index - 1) >> 1;
tree[index]++;
}
}
return crosscount;
}
reorder.count_crossings = count_crossings;

reorder.barycenter1 = function(graph, comp, iter) {
var nodes = graph.nodes(),
layer1, layer2,
Expand Down
2 changes: 1 addition & 1 deletion src/graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ reorder.graph = function(nodes, links, directed) {
}
}
if (ccomp.length) {
ccomp.sort();
ccomp.sort(function(a,b){ return a-b; });
comps.push(ccomp);
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ require("util").puts(JSON.stringify({
"devDependencies": {
"seedrandom": "2.3.11",
"uglify-js": "2.4.20",
"vows": "0.8.1"
"vows": "0.8.1",
"jsonfile": "2.0.0"
},
"licenses": [
{
Expand Down
74 changes: 0 additions & 74 deletions test/barycenter-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,6 @@ var vows = require("vows"),

var suite = vows.describe("reorder.barycenter");

function naive_count_crossings(graph, north, south) {
var i, j, e1, e2, v, count = 0,
inv_north = reorder.inverse_permutation(north),
inv_south = reorder.inverse_permutation(south),
links = [];
for (i = 0; i < north.length; i++) {
v = north[i];
links = links.concat(graph.outEdges(v).map(function(e) {
return [ inv_north[e.target.index], inv_south[e.source.index] ];
}));
}
for (i = 0; i < links.length; i++) {
e1 = links[i];
for (j = i+1; j < links.length; j++) {
e2 = links[j];
if ((e1[0] < e2[0] && e1[1] > e2[1])
|| (e1[0] > e2[0] && e1[1] < e2[1]))
count++;
}
}
return count;
}

suite.addBatch({
"barycenter": {
"simple": function() {
Expand All @@ -44,57 +21,6 @@ suite.addBatch({
perm = reorder.barycenter(graph);
reorder.printmat(mat, perm[1], perm[0]);
//assert.deepEqual(perm, expect);
},
"count_crossings": function() {
var graph = reorder.graph()
.nodes([{id: 0}, {id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 5}])
.links([{source: 0, target: 0},
{source: 1, target: 1},
{source: 1, target: 2},
{source: 2, target: 0},
{source: 2, target: 3},
{source: 2, target: 4},
{source: 3, target: 0},
{source: 3, target: 2},
{source: 4, target: 3},
{source: 5, target: 2},
{source: 5, target: 4}])
.directed(true)
.init(),
comp = graph.components()[0],
layer1 = comp.filter(function(n) {
return graph.outEdges(n).length!=0;
}),
layer2 = comp.filter(function(n) {
return graph.inEdges(n).length!=0;
});


assert.equal(naive_count_crossings(graph, layer1, layer2),
12);
assert.equal(reorder.count_crossings(graph, layer1, layer2),
12);
},
"count_crossings_hard": function() {
for (var i = 10; i < 100; i += 20) {
for (var j = 10; j < 100; j += 20) {
var mat = reorder.randomMatrix(0.2, i, j, false),
graph = reorder.mat2graph(mat, true),
comps = graph.components(),
comp = comps.reduce(function(a, b) {
return (a.length > b.length) ? a : b;
});
comp.sort();
var layer1 = comp.filter(function(n) {
return graph.outEdges(n).length!=0;
}),
layer2 = comp.filter(function(n) {
return graph.inEdges(n).length!=0;
});
assert.equal(reorder.count_crossings(graph, layer1, layer2),
naive_count_crossings(graph, layer1, layer2));
}
}
}
}
});
Expand Down
6 changes: 3 additions & 3 deletions test/ca-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ require("../reorder.v1");
require("../reorder.v1");

var vows = require("vows"),
assert = require("assert");
var seedrandom = require('seedrandom');
assert = require("assert"),
seedrandom = require('seedrandom');
Math.seedrandom('reorder');

var suite = vows.describe("reorder.ca");
Expand All @@ -20,7 +20,7 @@ suite.addBatch({
res = reorder.ca(mat, 0.0001);

//assert.isTrue(true);
assert.inDeltaArray(res, [0.5354605, 0.2626774, -0.8026722], 0.001);
assert.inDeltaArray(res, [-0.5354605, -0.2626774, 0.8026722], 0.001);
}
}
});
Expand Down

0 comments on commit 592273a

Please sign in to comment.