After (probably too much) effort, I was able to get a roughly 50% speed improvement over order
as it is.
a = Array.fill(2000, { 1.0.rand });
bench { 100.do { a.order } };
On my machine, this pretty consistently comes in around 1.96 - 1.99 seconds.
Now add a class: https://gist.github.com/jamshark70/f5baf35794c72955034fb136e7be7f00
And reimplement a quicksort to use optimized methods from the new class (pasted below).
The new version is about 1.31 - 1.33 seconds. 1.97 / 1.32 = 1.49… = ~50% improvement.
order
creates a new 2-element array for each input array element, and then has to index repeatedly into the sub-arrays. ArrayPair simply keeps a separate array for each “row,” so the comparison function can simply at1
directly to the right value instead of [index][0]
.
So then you can have the speed improvement of evaluating a slow “decorate” function only once per item, and better performance in order
too.
(
var qs1 = { |array, start(0), end(array.size-1), comparison({ |a, b| a < b })|
var pivot, pivotI, i1, i2;
if(end - start >= 2) { // must be at least 3 values for recursive branch
pivotI = rrand(start, end);
pivot = array.at1(pivotI);
i1 = start;
i2 = end;
while { i1 < i2 } {
case
// if @i1 should not come before pivot
{ comparison.value(pivot, array.at1(i1)) } {
// swap i1 to the upper partition
array.swap(i1, i2);
i2 = i2 - 1;
}
// else if i2 should come before pivot
{ comparison.value(array.at1(i2), pivot) } {
// swap i2 to the lower partition
array.swap(i1, i2);
i1 = i1 + 1;
}
{
i1 = i1 + 1;
if(i2 > i1) { i2 = i2 - 1 };
};
};
// here i1 == i2, but this may be the top of the low part, or bottom of the high part
// ensure that i1 is the bottom of the high part
if(comparison.(array.at1(i1), pivot)) {
i1 = i1 + 1;
};
qs1.(array, start, i1 - 1, comparison);
qs1.(array, i1, end, comparison);
} {
if(start < end) { // 2 values
if(comparison.(array.at1(end), array.at1(start))) {
array.swap(start, end);
};
};
};
array
};
if(a.size != 2000) { a = Array.fill(2000, { 1.0.rand }) };
bench { 100.do {
var b = ArrayPair.newFromPair(a.copy, (0 .. a.size-1));
qs1.(b);
b.array2 // order
} };
)
hjh