K-d tree: Difference between revisions

→‎Faster Alternative Version: Added dim template parameter to KdNode, more idiomatic D code.
(Added Kotlin)
(→‎Faster Alternative Version: Added dim template parameter to KdNode, more idiomatic D code.)
Line 565:
{{trans|C}}
This version performs less lookups. Compiled with DMD this version is two times slower than the C version. Compiled with ldc2 it's a little faster than the C version compiled with gcc.
<lang d>import std.stdio, std.algorithm, std.math, std.random, std.typecons;
 
struct KdNode(size_t dim) {
enum maxDim = 3;
double[maxDimdim] x;
 
struct KdNode {
double[maxDim] x;
KdNode* left, right;
}
 
// See QuickSelect method.
KdNode!dim* findMedian(size_t idx, size_t dim)(KdNode!dim[] nodes) pure nothrow @nogc {
auto start = nodes.ptr;
auto end = &nodes[$ - 1] + 1;
Line 584 ⟶ 582:
return start;
 
KdNode*auto md = start + (end - start) / 2;
 
while (true) {
Line 611 ⟶ 609:
}
 
KdNode!dim* makeTree(size_t dim, size_t i = 0)(KdNode!dim[] nodes)
pure nothrow @nogc {
if (!nodes.length)
return null;
 
auto n = nodes.findMedian!i(nodes);
if (n != null) {
enum i2 = (i + 1) % dim;
immutable size_t nPos = n - nodes.ptr;
n.left = makeTree!(dim, i2)(nodes[0 .. nPos]);
n.right = makeTree!(dim, i2)(nodes[nPos + 1 .. $]);
}
Line 627 ⟶ 625:
}
 
void nearest(size_t dim)(in KdNode!dim* root,
in ref KdNode!dim nd,
in size_t i,
ref const(KdNode!dim)* best,
ref double bestDist,
ref size_t nVisited) pure nothrow @safe @nogc {
static double dist(in ref KdNode!dim a, in ref KdNode!dim b)
pure nothrow @nogc {
typeof(KdNode.x[0])double result = 0;
static foreach (immutable i; staticIota!(0, .. dim))
result += (a.x[i] - b.x[i]) ^^ 2;
return result;
Line 668 ⟶ 666:
}
 
void randPt(size_t dim=3)(ref KdNode!dim v, ref Xorshift rng)
pure nothrow @safe @nogc {
static foreach (immutable i; staticIota!(0, .. dim))
v.x[i] = rng.uniform01;
}
 
void/// smallTest() {
unittest {
KdNode!2[] wp = [{[2, 3]}, {[5, 4]}, {[9, 6]},
{[4, 7]}, {[8, 1]}, {[7, 2]}];
KdNode!2 thisPt = {[9, 2]};
 
KdNode*auto root = makeTree!(2, 0)(wp);
 
const(KdNode!2)* found = null;
double bestDist = 0;
size_t nVisited = 0;
root.nearest!2(root, thisPt, 0, found, bestDist, nVisited);
 
writefln("WP tree:\n Searching for %s\n" ~
" Found %s, dist = %g\n Seen %d nodes.\n",
thisPt.x[0..2], found.x[0..2], sqrt(bestDist), nVisited);
}
 
void/// bigTest() {
unittest {
enum N = 1_000_000;
enum testRuns = 100_000;
 
auto bigTree = new KdNode!3[N];
auto rng = 1.Xorshift;
foreach (ref node; bigTree)
randPt(node, rng);
 
KdNode*auto root = makeTree!(3, 0)(bigTree);
KdNode!3 thisPt;
randPt(thisPt, rng);
 
const(KdNode!3)* found = null;
double bestDist = 0;
size_t nVisited = 0;
root.nearest!3(root, thisPt, 0, found, bestDist, nVisited);
 
writefln("Big tree (%d nodes):\n Searching for %s\n" ~ " Found %s, dist = %g\n Seen %d nodes.", N, thisPt.x, found.x, sqrt(bestDist), nVisited);
" Found %s, dist = %g\n Seen %d nodes.",
N, thisPt.x, found.x, sqrt(bestDist), nVisited);
 
size_t sum = 0;
Line 721 ⟶ 719:
sum += nVisited;
}
writefln("\nBig tree:\n Visited %d nodes for %d random " ~
"searches (%.2f per lookup).",
sum, testRuns, sum / double(testRuns));
}
}</lang>
 
void main() {
smallTest;
bigTest;
}</lang>
{{out}}
<pre>WP tree:
Anonymous user