HD7 Results
Hacker's Delight #7 Final Results
Problem & Constraints
- You will be provided with a cloud of no more than 65535 points
- The point cloud will not be a pathological case, such as points distributed in a regular grid pattern, on a surface of a sphere, or all on a single plane.
Rank |
Name |
Total Cycles |
Runs |
Time (ms) |
Per Run (ms) |
DQ |
Notes |
1 |
AlistairMilne_ElectronicArtsMontreal_submission2 | 57003397398 | 800 | 15834.28 | 19.79 | OK | - |
| Senzee_Tiburon_1 | 76097087667 | 800 | 21138.08 | 26.42 | DQ | run 50/800 incorrect | |
| AndySouthgate_EATech | 90699312924 | 800 | 25194.25 | 31.49 | DQ | run 293/800 incorrect | |
2 |
ColinAndrews_ElectronicArtsMaxis_sub7 | 131961781503 | 800 | 36656.05 | 45.82 | OK | - |
2 |
ColinAndrews_ElectronicArtsMaxis_sub6 | 132929517312 | 800 | 36924.87 | 46.16 | OK | - |
2 |
ColinAndrews_ElectronicArtsMaxis_sub8 | 133619520465 | 800 | 37116.54 | 46.40 | OK | - |
2 |
ColinAndrews_ElectronicArtsMaxis_sub1 | 138658942728 | 800 | 38516.37 | 48.15 | OK | - |
2 |
ColinAndrews_ElectronicArtsMaxis_sub3 | 139746436254 | 800 | 38818.45 | 48.52 | OK | - |
2 |
ColinAndrews_ElectronicArtsMaxis_sub5 | 140119140726 | 800 | 38921.98 | 48.65 | OK | - |
2 |
ColinAndrews_ElectronicArtsMaxis_sub4 | 142041002922 | 800 | 39455.84 | 49.32 | OK | - |
3 |
dwinter1_ElectronicArtsCanada | 163758314763 | 800 | 45488.42 | 56.86 | OK | - |
4 |
JayMacDonald_EAC | 191835150390 | 800 | 53287.54 | 66.61 | OK | - |
5 |
MichaelCooper_PolarSun | 235507388454 | 800 | 65418.72 | 81.77 | OK | - |
6 |
DavidGaleano_ElectronicArtsEATech_4 | 278949846951 | 800 | 77486.07 | 96.86 | OK | - |
7 |
LouisGascoigne_ElectronicArtsRedwoodShores_2 | 288767046564 | 800 | 80213.07 | 100.27 | OK | - |
8 |
DavidGaleano_ElectronicArtsEATech_2 | 319879085328 | 800 | 88855.30 | 111.07 | OK | - |
8 |
DavidGaleano_ElectronicArtsEATech_3 | 382839377481 | 800 | 106344.27 | 132.93 | OK | - |
9 |
LarzSmith_EATiburon | 711535278186 | 800 | 197648.69 | 247.06 | OK | - |
10 |
JeffreyRainy_ElectronicArtsCanada | 795788127657 | 800 | 221052.26 | 276.32 | OK | - |
| NathanHoobler_ElectronicArtsMythic | - | - | - | - | DQ | exception on certain sets | |
| NathanHoobler_ElectronicArtsMythic2 | - | - | - | - | DQ | exception on certain sets | |
| ColinAndrews_ElectronicArtsMaxis_sub2 | - | - | - | - | DQ | hangs on certain sets - the only dual threaded entry | |
| AlistairMilne_ElectronicArtsMontreal | - | - | - | - | DQ | hangs on certain sets | |
| Dom_EAC | - | - | - | - | DQ | exception on certain sets; some incorrect | |
| dwinter2_ElectronicArtsCanada | - | - | - | - | DQ | hangs on certain input sets | |
| PhilipDunstan_EATechUK_v2 | - | - | - | - | DQ | exception on certain input sets | |
| PhilipDunstan_EATechUK_v1 | - | - | - | - | DQ | incorrect answers on certain input sets | |
| YggyKing_ElectronicArtsCanada | - | - | - | - | DQ | hangs on certain input sets | |
11 |
Reference | - | - | - | 26257.13 | OK | - |
| Senzee_AlistairMilneAlgorithm_1 | 46818518994 | 800 | 13005.14 | 16.26 | OK | optimization of Alistair Milne's fastest entry |
Submissions
The entries we received used a variety of approaches. The canonical divide-and-conquer approach (see Cormen, Introduction to Algorithms, p.957), kd-trees, various sorting and hashing approaches were all represented. We even received one entry that was dual-threaded.
Fastest Entry
Alistair Milne's elegant second entry was fastest by a clear margin. And it's pure C++. It is a beautiful and simple algorithm that I was shocked not to find anywhere in the literature. Essentially, it's a quicksort based algorithm that's modified to traverse an implicit kd-tree. Alistair writes,
"It's basically a KD tree builder based on qsort, with some extra mess to cope with the overlaps between zones." Here's a paraphrase of the algorithm -
// partition all points less than sqrt(distancesq) away from the plane specified by pivot and coordinate (0 = x, 1 = y, 2 = z)
// into the lower part of the array and returns the final location of the pivot point
Point *PartitionByDistance(Point *lo, Point *hi, Point *pivot, unsigned coordinate, float distancesq);
// A normal quicksort median of 3 partition function that partitions based on the coordinate (0 = x, 1 = y, 2 = z) specified
Point *PartitionMedian3(Point *lo, Point *hi, unsigned coordinate);
// The naive O(N^2) function for small sets
float *GetMinDistSquared_Naive(Point *lo, Point *hi);
float GetMinDistSquared(Point *lo, Point *hi, float distancesq = FLT_MAX, unsigned depth = 0)
{
enum { N2_CUTOFF = .. }; // set to optimal threshold for N^2 algorithm
float d;
if (lo + N2_CUTOFF < hi)
{
unsigned coordinate = depth % 3;
// partition segment
Point *q = PartitionMedian3(lo, hi, coordinate);
// now recurse, divide and conquer
if ((d = GetMinDistSquared(lo, q - 1, distancesq, depth + 1)) < distancesq)
distancesq = d;
if ((d = GetMinDistSquared(q + 1, hi, distancesq, depth + 1)) < distancesq)
distancesq = d;
// now get any 'smallest' pairs that cross a partition
q = PartitionByDistance(lo, hi, q, coordinate, gMind);
if ((d = GetMinDistSquared(lo, q, distancesq, depth + 1)) < distancesq)
distancesq = d;
}
else if (lo < hi)
{
if ((d = GetMinDistSquared_Naive(lo, hi)) < distancesq)
distancesq = d;
}
return distancesq;
}
For interest, we created an SIMD optimized version of Alistair's algorithm. Thanks to the efforts of everyone who entered.
Paul D. Senzee
psenzee@ea.com