What does it take to test a sorting routine? (2010)
reprog.wordpress.com
reprog.wordpress.com
[1] https://docs.imandra.ai/imandra-docs/notebooks/verifying-mer...
Length 0: [].
Length 1: [0].
Length 2: [0,0], [0,1], [1,0], [1,1].
Length 3: [0,0,0], [0,0,1], [0,0,2], [0,1,0], [0,1,1], [0,1,2], ... [2,2,2]. (3^3 = 27 arrays in total)
Length 4: (4^4 = 256 arrays in total)
Length 5: (5^5 = 3125 arrays in total)
Length 6: (6^6 = 46656 arrays in total)
Length 7: (7^7 = 823543 arrays in total)
Length 8: (8^8 = 16777216 arrays in total)
Yeah, the latter should be caught by an isArray() check... which is the whole point.
Likewise for non-arrays.
It's notable that one of the participants had decided empty arrays shouldn't be a thing, so far as I know programming languages all admit the idea of the empty array although perhaps some of them don't distinguish between empty arrays and various other empty data structures.
It's not the first time I ended up wondering whether testing something rigorously is actually easier than implementing it correctly.
For some problems it is much easier to check that the result is correct than to find the result (that's what P and NP are about for example). Sorting is one of these problems. You can check that one list is a permutation of another list in linear time. Comparing against a library implementation of sorting is just simpler in many languages.
You don't have to sort to check sortedness.
boolean isSorted(int[] original, int[] sorted) {
if (original.length != sorted.length)
return false;
for (int i = 0; i < original.length; i++) {
if (i > 0 && sorted[i] < sorted[i - 1])
return false;
if (countInstances(original[i], original) != countIntasnces(original[i], sorted))
return false;
}
return true;
}
int countInstances(int value, int[] array) {
int count = 0;
for (int v : array) {
if (v == value)
count++;
}
return count;
}
I know that bubble sort, selection sort, and insertion sort can be implemented in about half the code as this. But this code is read-only and is more obviously correct than trying to prove an algorithm that mutates the array.isSorted([0, 0, 0], [4, 20, 0, 0, 0]) is true
(the code doesn't care about values in sorted which never occur in original and doesn't check these arrays are the same length)
But
isSorted([10, 5, 0], [0, 5, 10]) is false
(for some reason the code checks that original is sorted, rather than sorted...)
That's OK though, the original exercise exists because most programmers can't get even basic algorithms right, so you're helping to demonstrate that.
Added at the beginning of isSorted():
if (original.length != sorted.length)
return false;
Changed the wrong ordering check: if (i > 0 && original[i] < original[i - 1])
> most programmers can't get even basic algorithms right, so you're helping to demonstrate thatNow this puts my entire body of published work into question...
It's silly to reject help from e.g. peer review, static analysis, smarter / safer languages. If you look at some tool and say "What kind of idiot would make the mistakes this catches?" the answer is almost certainly "idiots like you".
In almost-Lua pseudocode:
function isOrdered(array, predicate)
-- zero and one length arrays are trivially ordered
if len(array) < 2 then return true end
local ordered = true
for i = 0, len(array) - 1 do
ordered = ordered and predicate(array[i], array + 1)
end
return ordered
end
function popCount(array)
local pops = {}
for item in iterate(array) do
pops = pops[item] and pops[item] + 1 or 1
end
return pops
end
Then you compare the two popcounts, if they're the same and the result is in-order then something made them that way.And he likes sushi.