Hi Juan,
Win 7, 1123:
I am seeing bad values returned by vector.Sn() for small vectors (i.e. lengths up to 64).
The script has both brute force and efficient PJSR implementations of unnormalized Sn for comparison purposes.
The ratio of the length 2 and 4 tests equals a "partial" Sn normalization factor. The additional factor of 1.1926 is missing per the Croux/Rousseeuw time-efficient algorithms paper.
But for the other cases I can't explain the ratio.
On many 64 length cases, I am getting from vector.Sn() what appear to be poor results.
Mike
array = [0.533087, -1.02232]
vector.Sn(): 1.1556674009999999
SnSlow(array): 1.5554069999999998
vector.Sn() / SnSlow(array): 0.743
SnFast(array): 1.5554069999999998
array = [0.533087, -1.02232, -0.855217]
vector.Sn(): 2.569750704
SnSlow(array): 0.1671029999999999
vector.Sn() / SnSlow(array): 15.378243981257079
SnFast(array): 0.1671029999999999
array = [0.533087, -1.02232, -0.855217, -0.364599]
vector.Sn(): 0.6274658339999999
SnSlow(array): 0.6577209999999999
vector.Sn() / SnSlow(array): 0.954
SnFast(array): 0.6577209999999999
array = [...]
vector.Sn(): 0.7659920000000001
SnSlow(array): 0.760739
vector.Sn() / SnSlow(array): 1.0069051277770695
SnFast(array): 0.760739
function sortCompare(a, b) {
return a < b ? -1 : a > b ? 1 : 0;
}
// brute force O(n^2)
function SnSlow(a) {
var n = a.length;
var a1 = new Array(n);
var a2 = new Array(n);
for (var i = 0; i != n; ++i) {
for (var j = 0; j != n; ++j) {
a1[j] = Math.abs(a[i] - a[j]);
}
a1.sort(sortCompare);
a2[i] = a1[Math.floor(n / 2)]; // high median
}
a2.sort(sortCompare);
return a2[Math.floor((n + 1) / 2) - 1]; // low median
}
// efficient O(n log n)
function SnFast(x1) { // ?
var x = x1.slice(0, x1.length);
x.sort(sortCompare);
var n = x.length;
if (n == 0) {
return 0;
}
var y = new Array(n);
y[0] = x[Math.floor(n / 2)] - x[0];
for (var i = 2; i <= Math.floor((n + 1) / 2); ++i) {
var nA = i - 1;
var nB = n - i;
var diff = nB - nA;
var leftA = 1;
var leftB = 1;
var rightA = nB;
var rightB = nB;
var Amin = Math.floor(diff / 2) + 1;
var Amax = Math.floor(diff / 2) + nA;
while (true) {
if (leftA < rightA) {
var length = rightA - leftA + 1;
var even = 1 - Math.mod(length, 2);
var half = Math.floor((length - 1) / 2);
var tryA = leftA + half;
var tryB = leftB + half;
if (tryA < Amin) {
rightB = tryB;
leftA = tryA + even;
}
else {
if (tryA > Amax) {
rightA = tryA;
leftB = tryB + even;
}
else {
var medA = x[i - 1] - x[i - tryA + Amin - 1 - 1];
var medB = x[tryB + i - 1] - x[i - 1];
if (medA >= medB) {
rightA = tryA;
leftB = tryB + even;
}
else {
rightB = tryB;
leftA = tryA + even;
}
}
}
}
else {
if (leftA > Amax) {
y[i - 1] = x[leftB + i - 1] - x[i - 1];
}
else {
var medA = x[i - 1] - x[i - leftA + Amin - 1 - 1];
var medB = x[leftB + i - 1] - x[i - 1];
y[i - 1] = Math.min(medA, medB);
}
break;
}
}
}
for (var i = Math.floor((n + 1) / 2) + 1; i <= n - 1; ++i) {
var nA = n - i;
var nB = i - 1;
var diff = nB - nA;
var leftA = 1;
var leftB = 1;
var rightA = nB;
var rightB = nB;
var Amin = Math.floor(diff / 2) + 1;
var Amax = Math.floor(diff / 2) + nA;
while (true) {
if (leftA < rightA) {
var length = rightA - leftA + 1;
var even = 1 - Math.mod(length, 2);
var half = Math.floor((length - 1) / 2);
var tryA = leftA + half;
var tryB = leftB + half;
if (tryA < Amin) {
rightB = tryB;
leftA = tryA + even;
}
else {
if (tryA > Amax) {
rightA = tryA;
leftB = tryB + even;
}
else {
var medA = x[i + tryA - Amin + 1 - 1] - x[i - 1];
var medB = x[i - 1] - x[i - tryB - 1];
if (medA >= medB) {
rightA = tryA;
leftB = tryB + even;
}
else {
rightB = tryB;
leftA = tryA + even;
}
}
}
}
else {
if (leftA > Amax) {
y[i - 1] = x[i - 1] - x[i - leftB - 1];
}
else {
var medA = x[i + leftA - Amin + 1 - 1] - x[i - 1];
var medB = x[i - 1] - x[i - leftB - 1];
y[i - 1] = Math.min(medA, medB);
}
break;
}
}
}
y[n - 1] = x[n - 1] - x[Math.floor((n + 1) / 2) - 1];
y.sort(sortCompare);
return y[Math.floor((n + 1) / 2) - 1];
}
console.writeln();
var array = [0.533087, -1.02232]; //, -0.855217]; // , -0.364599];
console.write("array = [");
for (var i = 0; i != array.length -1; ++i) {
console.write(array[i], ", ");
}
console.writeln(array[array.length - 1], "]");
var vector = new Vector(array.length);
vector.assign(array, 0, array.length);
console.writeln("vector.Sn(): ", vector.Sn());
console.writeln("SnSlow(array): ", SnSlow(array));
console.writeln("vector.Sn() / SnSlow(array): ", vector.Sn() / SnSlow(array));
console.writeln("SnFast(array): ", SnFast(array));
console.writeln();
var array = [0.533087, -1.02232, -0.855217]; // , -0.364599];
console.write("array = [");
for (var i = 0; i != array.length -1; ++i) {
console.write(array[i], ", ");
}
console.writeln(array[array.length - 1], "]");
var vector = new Vector(array.length);
vector.assign(array, 0, array.length);
console.writeln("vector.Sn(): ", vector.Sn());
console.writeln("SnSlow(array): ", SnSlow(array));
console.writeln("vector.Sn() / SnSlow(array): ", vector.Sn() / SnSlow(array));
console.writeln("SnFast(array): ", SnFast(array));
console.writeln();
var array = [0.533087, -1.02232, -0.855217, -0.364599];
console.write("array = [");
for (var i = 0; i != array.length -1; ++i) {
console.write(array[i], ", ");
}
console.writeln(array[array.length - 1], "]");
var vector = new Vector(array.length);
vector.assign(array, 0, array.length);
console.writeln("vector.Sn(): ", vector.Sn());
console.writeln("SnSlow(array): ", SnSlow(array));
console.writeln("vector.Sn() / SnSlow(array): ", vector.Sn() / SnSlow(array));
console.writeln("SnFast(array): ", SnFast(array));
console.writeln();
var array = [0.533087, -1.02232, -0.855217, -0.364599, 1.46429, 0.756261,
2.17472, -0.0421965, 0.627769, -0.655922, 0.256595, -0.838173,
0.642002, -1.42016, 0.460509, 0.160264, 0.132564, -0.722706,
0.347617, 0.698298, -1.64382, 0.254763, 0.771643, -2.38453,
-0.810664, -1.07687, 0.191627, -0.676371, -0.818345, 1.37031,
0.140143, -1.12645, 0.314962, 0.84163, 0.0156415, -0.584815, 0.36632,
-1.75322, 0.417046, 0.445999, 2.18433, 1.19637, -0.108828, 0.219621,
0.651911, -0.999894, -0.993649, -1.28664, -0.455387, -0.234295,
-0.12633, -0.238317, -1.08056, -0.393563, 0.108105, -0.169317,
-0.12739, 0.171254, 0.605376, 0.619183, 0.782824, 1.39034, 0.911639,
-1.25819];
console.writeln("array = [...]");
var vector = new Vector(array.length);
vector.assign(array, 0, array.length);
console.writeln("vector.Sn(): ", vector.Sn());
console.writeln("SnSlow(array): ", SnSlow(array));
console.writeln("vector.Sn() / SnSlow(array): ", vector.Sn() / SnSlow(array));
console.writeln("SnFast(array): ", SnFast(array));