K-d tree: Difference between revisions

112,261 bytes added ,  2 months ago
m (C++ - simplified code)
 
(16 intermediate revisions by 10 users not shown)
Line 28:
Also there are algorithms for inserting, deleting, and balancing k-d trees.
These are also not required for the task.
=={{header|AArch64 Assembly}}==
{{works with|as|Raspberry Pi 3B version Buster 64 bits <br> or android 64 bits with application Termux }}
<syntaxhighlight lang AArch64 Assembly>
/* ARM assembly AARCH64 Raspberry PI 3B */
/* program kdtree64.s */
 
/* the coordinates of the points are integers numbers.
The displayed distance represents the square of the distance between 2 points */
/* This program draws heavily from the published C program. Thanks to its creator. */
/************************************/
/* Constantes */
/************************************/
.include "../includeConstantesARM64.inc"
 
.equ MAXI, 3
.equ NBPOINTSRAND, 2000
.equ MAXCOORD, 10000
 
 
/***********************************************/
/* structures */
/**********************************************/
/* Définition node */
.struct 0
nodeKD_val: // value array
.struct nodeKD_val + (8 * MAXI)
nodeKD_left: // left pointer
.struct nodeKD_left + 8
nodeKD_right: // right pointer
.struct nodeKD_right + 8
nodeKD_end:
/*********************************/
/* Initialized data */
/*********************************/
.data
szMessAddressTree: .asciz "Node address : "
szMessTreeValue: .asciz " Value : "
szMessLeft: .asciz " Left : "
szMessRight: .asciz " Right : "
szMessResult: .asciz "Nearest point = "
szMessRandCoor: .asciz "\n\nRandom point coordonnés = "
szMessVisited: .asciz "Node visited = "
szMessDistance: .asciz "square distance :"
szMessStart: .asciz "Program 64 bits start.\n"
szCarriageReturn: .asciz "\n"
.align 4
tabPoint1: .quad 2,3, 5,4, 9,6, 4,7, 8,1, 7,2
//tabPoint1: .quad 1,7, 3,4, 4,6, 6,2, 8,12, 10,9, 12,3, 14,1
//tabPoint1: .quad 3,5, 1,3, 2,8, 4,6, 5,4
.equ NBPOINTS, (. - tabPoint1) / 8
 
tabPoint2: .quad 9,2
//tabPoint2: .quad 3,7
.equ NBPOINTS2, (. - tabPoint2) / 8
 
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
stNode1: .skip nodeKD_end
KDtree1: .skip nodeKD_end * NBPOINTS
KDtree2: .skip nodeKD_end * NBPOINTS2
KdtreeRand: .skip nodeKD_end * NBPOINTSRAND
tabPointsRand: .skip nodeKD_end
sZoneConv: .skip 24 // conversion buffer
sZoneConv1: .skip 24 // conversion buffer
sBufferConv16: .skip 24
iDistance: .skip 8 // best distance
stNearest: .skip nodeKD_end // best node
nbNodeVi: .skip 8 // visited node
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: // entry of program
ldr x0,qAdrszMessStart
bl affichageMess
ldr x0,qAdrtabPoint1 // points array address
ldr x1,qAdrKDtree1 // KD tree address
mov x2,#NBPOINTS // array points size
mov x3,#2 // domension 2
bl initKDTree // init tree
ldr x0,qAdrKDtree1 // KD tree address
mov x1,#0 // start index
mov x2,#NBPOINTS / 2 // end = array points size
mov x3,#0 // level
mov x4,#2 // dimension 2
bl createTree
mov x8,x0 // save median
cmp x0,#-1
beq 100f
ldr x0,qAdrKDtree1 // KD tree address
mov x1,#2 // dimension 2
bl displayTree
ldr x0,qAdrtabPoint2 // points array address
ldr x1,qAdrKDtree2 // search KDtree address
mov x2,#NBPOINTS2 // search array points size
mov x3,#2 // dimension 2
bl initKDTree // init search tree
ldr x0,qAdrKDtree1 // KDtree address
mov x1,#nodeKD_end
madd x0,x8,x1,x0 // compute median address
ldr x1,qAdrKDtree2 // search KDtree address
mov x2,#0 // first index
mov x3,#2 // dimension 2
bl searchNearest // search nearest point
ldr x0,qAdrszMessResult // display résult
bl affichageMess
ldr x0,qAdrstNearest // nearest point address
ldr x0,[x0]
mov x1,#2
bl displayCoord // coordonnés display
ldr x0,qAdrnbNodeVi // visited nodes
ldr x0,[x0]
ldr x1,qAdrsZoneConv
bl conversion10
mov x0,#3
ldr x1,qAdrszMessVisited
ldr x2,qAdrsZoneConv
ldr x3,qAdrszCarriageReturn
bl displayStrings
ldr x0,qAdriDistance // best distance address
ldr x0,[x0]
ldr x1,qAdrsZoneConv
bl conversion10
mov x0,#3
ldr x1,qAdrszMessDistance
ldr x2,qAdrsZoneConv
ldr x3,qAdrszCarriageReturn
bl displayStrings
bl traitRandom
100: // standard end of the program
mov x0, #0 // return code
mov x8,EXIT
svc #0 // perform the system call
qAdrszCarriageReturn: .quad szCarriageReturn
qAdrsZoneConv: .quad sZoneConv
qAdrszMessDistance: .quad szMessDistance
qAdrszMessResult: .quad szMessResult
qAdrszMessVisited: .quad szMessVisited
qAdrszMessStart: .quad szMessStart
qAdrtabPoint1: .quad tabPoint1
qAdrtabPoint2: .quad tabPoint2
qAdrKDtree1: .quad KDtree1
qAdrKDtree2: .quad KDtree2
/***************************************************/
/* traitement random points */
/***************************************************/
traitRandom:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
ldr x8,qAdrKdtreeRand // KD tree address
mov x7,#nodeKD_end
ldr x10,iNbPointsRand
mov x3,#0
1: // loop generate random coordonnes
mov x0,0
mov x1,#MAXCOORD
bl extRandom // X
mov x4,x0
mov x0,0
mov x1,#MAXCOORD
bl extRandom // Y
mov x5,x0
mov x0,0
mov x1,#MAXCOORD
bl extRandom // Z
mov x6,x0
madd x0,x3,x7,x8
add x1,x0,#nodeKD_val // node address
str x4,[x1] // store X,Y,Z
str x5,[x1,#8]
str x6,[x1,#16]
mov x4,#-1 // init pointer left and right
str x4,[x0,#nodeKD_left]
str x4,[x0,#nodeKD_right]
add x3,x3,#1
cmp x3,x10
blt 1b
mov x0,x8 // KD tree address
mov x1,#0 // start indice
mov x2,x10 // array points size
mov x3,#0 // level
mov x4,#3 // dimension 2
bl createTree
mov x9,x0 // save median
// create random search point
mov x0,0
mov x1,#MAXCOORD
bl extRandom
mov x4,x0
mov x0,0
mov x1,#MAXCOORD
bl extRandom
mov x5,x0
mov x0,0
mov x1,#MAXCOORD
bl extRandom
mov x6,x0
ldr x3,qAdrtabPointsRand
add x0,x3,#nodeKD_val
str x4,[x0]
str x5,[x0,#8]
str x6,[x0,#16]
ldr x0,qAdrszMessRandCoor
bl affichageMess
mov x0,x3
mov x1,#3
bl displayCoord // search
ldr x0,qAdriDistance // init best distance address
mov x1,#0
str x1,[x0]
madd x0,x9,x7,x8 // median KD tree address
mov x1,x3 // search point address
mov x2,#0 // index
mov x3,#3 // dimension 2
bl searchNearest
ldr x0,qAdrszMessResult
bl affichageMess
ldr x0,qAdrstNearest
ldr x0,[x0]
mov x1,#3
bl displayCoord
ldr x0,qAdrnbNodeVi
ldr x0,[x0]
ldr x1,qAdrsZoneConv
bl conversion10
mov x0,#3
ldr x1,qAdrszMessVisited
ldr x2,qAdrsZoneConv
ldr x3,qAdrszCarriageReturn
bl displayStrings
ldr x0,qAdriDistance // best distance address
ldr x0,[x0]
ldr x1,qAdrsZoneConv
bl conversion10
mov x0,#3
ldr x1,qAdrszMessDistance
ldr x2,qAdrsZoneConv
ldr x3,qAdrszCarriageReturn
bl displayStrings
100:
ldp x2,x3,[sp],16 // restaur registers
ldp x1,lr,[sp],16 // restaur registers
ret
qAdrKdtreeRand: .quad KdtreeRand
qAdrtabPointsRand: .quad tabPointsRand
qAdrszMessRandCoor: .quad szMessRandCoor
iNbPointsRand: .quad NBPOINTSRAND
/***************************************************/
/* init KN tree */
/***************************************************/
/* x0 array points */
/* x1 array tree address */
/* x2 points number */
/* x3 dimension */
initKDTree:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
stp x4,x5,[sp,-16]! // save registers
stp x6,x7,[sp,-16]! // save registers
stp x8,x9,[sp,-16]! // save registers
mov x8,#0 // points indice
mov x4,#0 // node tree indice
mov x6,#nodeKD_end // structure size
1:
madd x5,x4,x6,x1 // compute node address
mov x9,#0 // index value
2:
ldr x7,[x0,x8,lsl #3] // load one point coord
str x7,[x5,x9,lsl #3] // store in node value
add x8,x8,#1 // next point
add x9,x9,#1 // next node value
cmp x9,x3 // = dimension ?
blt 2b // no loop
mov x7,#-1 // init pointer left and right
str x7,[x5,#nodeKD_left]
str x7,[x5,#nodeKD_right]
add x4,x4,#1 // increment node tree indice
cmp x8,x2 // end points ?
blt 1b
100:
ldp x8,x9,[sp],16 // restaur registers
ldp x6,x7,[sp],16 // restaur registers
ldp x4,x5,[sp],16 // restaur registers
ldp x2,x3,[sp],16 // restaur registers
ldp x1,lr,[sp],16 // restaur registers
ret
/***************************************************/
/* create KD tree */
/***************************************************/
/* x0 array tree address */
/* x1 start index */
/* x2 end index
/* x3 level */
/* x4 dimention */
createTree:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
stp x4,x5,[sp,-16]! // save registers
stp x6,x7,[sp,-16]! // save registers
stp x8,x9,[sp,-16]! // save registers
stp x10,x11,[sp,-16]! // save registers
stp x12,x13,[sp,-16]! // save registers
cmp x1,x2 // if start = end -> return -1
mov x5,-1
csel x0,x5,x0,ge
//movge x0,#-1
bge 100f
add x5,x1,#1 // if start + 1 = end -> return start
cmp x5,x2
csel x0,x1,x0,eq
//moveq x0,x1
beq 100f
mov x8,x0 // save address
mov x7,x1 // save start index
mov x12,x2 // save end index
mov x5,x3 // save level
mov x10,x4 // save dimension
mov x9,#nodeKD_end // node structure size
mov x1,x7 // start
mov x2,x12 // end
bl findMedian
cmp x0,#0 //
mov x6,-1
csel x0,x6,x0,lt
//movlt x0,#-1
blt 100f
mov x6,x0 // save indice median
add x5,x5,#1 // compute new value index
cmp x5,x10 // => dimension ?
csel x5,xzr,x5,ge
//movge x5,#0
mov x0,x8 // tree address
mov x1,x7 // start
mov x2,x6 // end = median
mov x3,x5 // index
mov x4,x10 // dimension
bl createTree
madd x1,x6,x9,x8 // compute median address
cmp x0,#-1 // left address is ok ?
beq 1f
madd x0,x9,x0,x8 // yes compute address
1:
str x0,[x1,#nodeKD_left] // and store
mov x0,x8 // KDtree address
add x1,x6,#1 // start = indice median + 1
mov x2,x12 // end
mov x3,x5 // index
mov x4,x10 // dimension
bl createTree
madd x1,x6,x9,x8 // compute median address
cmp x0,#-1 // indice right ok ?
beq 2f
madd x0,x9,x0,x8 // yes compute address
2:
str x0,[x1,#nodeKD_right] // and store in pointer
mov x0,x6 // return indice median node
100:
ldp x12,x13,[sp],16 // restaur registers
ldp x10,x11,[sp],16 // restaur registers
ldp x8,x9,[sp],16 // restaur registers
ldp x6,x7,[sp],16 // restaur registers
ldp x4,x5,[sp],16 // restaur registers
ldp x2,x3,[sp],16 // restaur registers
ldp x1,lr,[sp],16 // restaur registers
ret
/***************************************************/
/* find median and sort points */
/***************************************************/
/* x0 tree address */
/* x1 start tree indice
/* x2 end tree indice */
/* x3 indice */
/* x0 return median point index */
findMedian:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
stp x4,x5,[sp,-16]! // save registers
stp x6,x7,[sp,-16]! // save registers
stp x8,x9,[sp,-16]! // save registers
stp x10,x11,[sp,-16]! // save registers
stp x12,x13,[sp,-16]! // save registers
cmp x2,x1
mov x7,-1
csel x0,x7,x0,le
//movle x0,#-1
ble 100f
mov x7,#nodeKD_end // node size
add x5,x1,#1 // next node address
cmp x2,x5 // equal to end ?
csel x0,x1,x0,eq
//moveq x0,x1
beq 100f // yes return
mov x8,x1 // save start
mov x12,x0 // save tree address
add x4,x2,x1 // end + start
lsr x9,x4,#1 // divide by 2 = median index
madd x10,x7,x9,x0 // mediam md address
lsl x5,x3,#2 // index * 4
1:
cmp x2,x8 // end <= start
csel x0,x2,x0,le // stop ?
//movle x0,x2 // stop ?
ble 100f
add x6,x10,#nodeKD_val
add x11,x6,x5 // add shift index
ldr x6,[x11] // load pivot value
mov x0,x10 // median address
sub x1,x2,#1 // compute address end - 1
mul x1,x7,x1
add x1,x1,x12
bl inversion // inversion median and end - 1
mov x11,x8 // store=indice start
mov x4,x8 // p =indice start
2:
cmp x4,x2 // compare p and end
bge 5f
madd x3,x4,x7,x12 // compute p address
add x3,x3,x5 // add shift index
ldr x0,[x3] // load value
cmp x0,x6 // compare to pivot
bge 4f
cmp x4,x11 // compare p et store
beq 3f
madd x0,x4,x7,x12 // compute p address
madd x1,x11,x7,x12 // compute store address
bl inversion // inversion p and store
3:
add x11,x11,#1 // increment store
4:
add x4,x4,#1 // increment p
b 2b
5:
csel x0,x9,x0,eq // equal return median index
//moveq x0,x9 // equal return median index
beq 100f
madd x0,x11,x7,x12 // store address
sub x1,x2,#1 // end - 1
madd x1,x7,x1,x12 // compute address
bl inversion // inversion store and end - 1
ldr x0,[x0,#nodeKD_val] // load store value
add x0,x0,x5 // add shift index
ldr x1,[x10,#nodeKD_val] // load median value
add x1,x1,x5 // add shift index
cmp x0,x1 // compare values
csel x0,x9,x0,eq // equal return median index
// moveq x0,x9 // equal return median index
beq 100f
cmp x11,x9 // compare index store and median
csel x2,x11,x2,gt // new end
csel x8,x11,x8,le // new start
//movgt x2,x11 // new end
//movle x8,x11 // new start
b 1b // and loop
 
100:
ldp x12,x13,[sp],16 // restaur registers
ldp x10,x11,[sp],16 // restaur registers
ldp x8,x9,[sp],16 // restaur registers
ldp x6,x7,[sp],16 // restaur registers
ldp x4,x5,[sp],16 // restaur registers
ldp x2,x3,[sp],16 // restaur registers
ldp x1,lr,[sp],16 // restaur registers
ret
/***************************************************/
/* compute distanceo 2 */
/***************************************************/
/* x0 tree node address */
/* x1 search points address */
/* x2 dimension */
distance:
stp x3,lr,[sp,-16]! // save registers
stp x4,x5,[sp,-16]! // save registers
stp x6,x7,[sp,-16]! // save registers
add x0,x0,#nodeKD_val // root node values array address
add x1,x1,#nodeKD_val // search node values array addresse
mov x3,#0 // first value index
mov x7,#0 // init distance
1:
ldr x4,[x0,x3,lsl #3] // load value
ldr x5,[x1,x3,lsl #3] // load value
sub x6,x5,x4 // différence
add x3,x3,#1
madd x7,x6,x6,x7 // compute square TODO: overflow
cmp x3,x2 // end ?
blt 1b // no -> loop
mov x0,x7 // return distance
100:
ldp x6,x7,[sp],16 // restaur registers
ldp x4,x5,[sp],16 // restaur registers
ldp x3,lr,[sp],16 // restaur registers
ret
/***************************************************/
/* search nearest point */
/***************************************************/
/* x0 tree address */
/* x1 search points address */
/* x2 index */
/* x3 dimension */
searchNearest:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
stp x4,x5,[sp,-16]! // save registers
stp x6,x7,[sp,-16]! // save registers
stp x8,x9,[sp,-16]! // save registers
stp x10,x11,[sp,-16]! // save registers
stp x12,x13,[sp,-16]! // save registers
cmp x0,#-1
beq 100f
mov x7,x0 // start with median
mov x8,x1 // save serach point address
lsl x9,x2,#2 // shift index
mov x10,x3 // save dimension
mov x2,x3 // dimension
bl distance // compute distance
mov x11,x0
ldr x1,[x7,x9]
ldr x12,[x8,x9]
sub x12,x12,x1
mul x6,x12,x12 // distance axis
ldr x4,qAdriDistance
ldr x5,[x4]
cmp x5,#0 // first distance ?
csel x5,x11,x5,eq
csel x3,x7,x3,eq
//moveq x5,x11 // new best distance
//moveq x3,x7 // new best node
beq 1f
cmp x11,x5 // compare new distance and best distance
bgt 2f
mov x5,x11 // new best distance
mov x3,x7 // new best node
1:
str x5,[x4] // store new best distance
ldr x4,qAdrstNearest // and store best node address
str x3,[x4]
2:
ldr x1,qAdrnbNodeVi // increment visited node
ldr x3,[x1]
add x3,x3,#1
str x3,[x1]
cmp x5,#0 // distance = 0 -> end //
beq 100f
cmp x12,#0 // else search in childen tree
bge 3f
ldr x0,[x7,#nodeKD_left]
b 4f
3:
ldr x0,[x7,#nodeKD_right]
4:
mov x1,x8
lsr x2,x9,#2
add x2,x2,#1
cmp x2,x10
csel x2,xzr,x2,ge
//movge x2,#0
mov x3,x10
bl searchNearest
ldr x4,qAdriDistance // best distance
ldr x5,[x4]
cmp x6,x5 // compare distance
bge 100f
cmp x12,#0 // else search in childen tree
blt 5f
ldr x0,[x7,#nodeKD_left]
b 6f
5:
ldr x0,[x7,#nodeKD_right]
6:
bl searchNearest
100:
ldp x12,x13,[sp],16 // restaur registers
ldp x10,x11,[sp],16 // restaur registers
ldp x8,x9,[sp],16 // restaur registers
ldp x6,x7,[sp],16 // restaur registers
ldp x4,x5,[sp],16 // restaur registers
ldp x2,x3,[sp],16 // restaur registers
ldp x1,lr,[sp],16 // restaur registers
ret
qAdrstNearest: .quad stNearest
qAdriDistance: .quad iDistance
qAdrnbNodeVi: .quad nbNodeVi
/***************************************************/
/* inversion */
/***************************************************/
/* x0 tree address */
/* x1 tree */
inversion:
stp x2,lr,[sp,-16]! // save registers
stp x3,x4,[sp,-16]! // save registers
add x0,x0,#nodeKD_val
add x1,x1,#nodeKD_val
mov x2,#0
1:
ldr x4,[x0,x2,lsl #3]
ldr x3,[x1,x2,lsl #3]
str x3,[x0,x2,lsl #3]
str x4,[x1,x2,lsl #3]
add x2,x2,#1
cmp x2,#MAXI
blt 1b
100:
ldp x3,x4,[sp],16 // restaur registers
ldp x2,lr,[sp],16 // restaur registers
ret
/***************************************************/
/* display tree */
/***************************************************/
/* x0 tree address */
/* x1 dimension */
displayTree:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
stp x4,x5,[sp,-16]! // save registers
stp x6,x7,[sp,-16]! // save registers
stp x8,x9,[sp,-16]! // save registers
stp x10,x11,[sp,-16]! // save registers
stp x12,x13,[sp,-16]! // save registers
mov x10,x0
mov x7,x1
mov x11,#0
mov x12,#nodeKD_end
1:
madd x9,x12,x11,x10
mov x0,x9
ldr x1,qAdrsBufferConv16
bl conversion16
mov x0,#2
ldr x1,qAdrszMessAddressTree
ldr x2,qAdrsBufferConv16
bl displayStrings
mov x8,#0
2:
add x4,x9,#nodeKD_val
ldr x0,[x4,x8,lsl #3]
ldr x1,qAdrsZoneConv
bl conversion10
mov x0,#2
ldr x1,qAdrszMessTreeValue
ldr x2,qAdrsZoneConv
bl displayStrings
add x8,x8,#1
cmp x8,x7
blt 2b
ldr x0,qAdrszCarriageReturn
bl affichageMess
add x0,x9,#nodeKD_left
ldr x0,[x0]
ldr x1,qAdrsZoneConv
bl conversion16
add x0,x9,#nodeKD_right
ldr x0,[x0]
ldr x1,qAdrsZoneConv1
bl conversion16
mov x0,#5
ldr x1,qAdrszMessLeft
ldr x2,qAdrsZoneConv
ldr x3,qAdrszMessRight
ldr x4,qAdrsZoneConv1
ldr x5,qAdrszCarriageReturn
bl displayStrings
add x11,x11,#1
cmp x11,#NBPOINTS / 2
blt 1b
100:
ldp x12,x13,[sp],16 // restaur registers
ldp x10,x11,[sp],16 // restaur registers
ldp x8,x9,[sp],16 // restaur registers
ldp x6,x7,[sp],16 // restaur registers
ldp x4,x5,[sp],16 // restaur registers
ldp x2,x3,[sp],16 // restaur registers
ldp x1,lr,[sp],16 // restaur registers
ret
qAdrszMessAddressTree: .quad szMessAddressTree
qAdrszMessTreeValue: .quad szMessTreeValue
qAdrsBufferConv16: .quad sBufferConv16
qAdrszMessLeft: .quad szMessLeft
qAdrszMessRight: .quad szMessRight
qAdrsZoneConv1: .quad sZoneConv1
/***************************************************/
/* display node coordonnées */
/***************************************************/
/* x0 node address */
/* x1 dimension */
displayCoord:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
stp x4,x5,[sp,-16]! // save registers
add x4,x0,#nodeKD_val
mov x3,x1 // save dimension
mov x5,#0
1:
ldr x0,[x4,x5,lsl #3]
ldr x1,qAdrsZoneConv
bl conversion10
mov x0,#2
ldr x1,qAdrszMessTreeValue
ldr x2,qAdrsZoneConv
bl displayStrings
add x5,x5,#1
cmp x5,x3
blt 1b
ldr x0,qAdrszCarriageReturn
bl affichageMess
100:
ldp x4,x5,[sp],16 // restaur registers
ldp x2,x3,[sp],16 // restaur registers
ldp x1,lr,[sp],16 // restaur registers
ret
/***************************************************/
/* display multi strings */
/* new version 24/05/2023 */
/***************************************************/
/* x0 contains number strings address */
/* x1 address string1 */
/* x2 address string2 */
/* x3 address string3 */
/* x4 address string4 */
/* x5 address string5 */
/* x6 address string5 */
/* x7 address string6 */
displayStrings: // INFO: displayStrings
stp x8,lr,[sp,-16]! // save registers
stp x2,fp,[sp,-16]! // save registers
add fp,sp,#32 // save paraméters address (4 registers saved * 8 bytes)
mov x8,x0 // save strings number
cmp x8,#0 // 0 string -> end
ble 100f
mov x0,x1 // string 1
bl affichageMess
cmp x8,#1 // number > 1
ble 100f
mov x0,x2
bl affichageMess
cmp x8,#2
ble 100f
mov x0,x3
bl affichageMess
cmp x8,#3
ble 100f
mov x0,x4
bl affichageMess
cmp x8,#4
ble 100f
mov x0,x5
bl affichageMess
cmp x8,#5
ble 100f
mov x0,x6
bl affichageMess
cmp x8,#6
ble 100f
mov x0,x7
bl affichageMess
100:
ldp x2,fp,[sp],16 // restaur registers
ldp x8,lr,[sp],16 // restaur registers
ret
/******************************************************************/
/* random number */
/******************************************************************/
/* x0 contains inferior value */
/* x1 contains maxi value */
/* x0 return random number */
extRandom:
stp x1,lr,[sp,-16]! // save registers
stp x2,x8,[sp,-16]! // save registers
stp x19,x20,[sp,-16]! // save registers
sub sp,sp,16 // reserve 16 octets on stack
mov x19,x0
add x20,x1,1
mov x0,sp // store result on stack
mov x1,8 // length 8 bytes
mov x2,0
mov x8,278 // call system Linux 64 bits Urandom
svc 0
mov x0,sp // load résult on stack
ldr x0,[x0]
sub x2,x20,x19 // calculation of the range of values
udiv x1,x0,x2 // calculation range modulo
msub x0,x1,x2,x0
add x0,x0,x19 // and add inferior value
100:
add sp,sp,16 // alignement stack
ldp x19,x20,[sp],16 // restaur 2 registers
ldp x2,x8,[sp],16 // restaur 2 registers
ldp x1,lr,[sp],16 // restaur 2 registers
ret // retour adresse lr x30
 
/***************************************************/
/* ROUTINES INCLUDE */
/***************************************************/
.include "../includeARM64.inc"
 
</syntaxhighlight>
{{Out}}
<pre>
Program 64 bits start.
Node address : 0000000000420628 Value : 2 Value : 3
Left : FFFFFFFFFFFFFFFF Right : FFFFFFFFFFFFFFFF
Node address : 0000000000420650 Value : 9 Value : 6
Left : 0000000000420628 Right : 0000000000420678
Node address : 0000000000420678 Value : 5 Value : 4
Left : FFFFFFFFFFFFFFFF Right : FFFFFFFFFFFFFFFF
Node address : 00000000004206A0 Value : 7 Value : 2
Left : 0000000000420650 Right : 00000000004206F0
Node address : 00000000004206C8 Value : 8 Value : 1
Left : FFFFFFFFFFFFFFFF Right : FFFFFFFFFFFFFFFF
Node address : 00000000004206F0 Value : 4 Value : 7
Left : 00000000004206C8 Right : FFFFFFFFFFFFFFFF
Nearest point = Value : 8 Value : 1
Node visited = 3
square distance :2
 
 
Random point coordonnés = Value : 6981 Value : 1946 Value : 4127
Nearest point = Value : 6561 Value : 1995 Value : 5172
Node visited = 95
square distance :1270826
</pre>
=={{header|ARM Assembly}}==
{{works with|as|Raspberry Pi <br> or android 32 bits with application Termux}}
<syntaxhighlight lang ARM Assembly>
/* ARM assembly Raspberry PI */
/* program kdtree.s */
 
/* REMARK 1 : this program use routines in a include file
see task Include a file language arm assembly
for the routine affichageMess conversion10
see at end of this program the instruction include */
/* REMARK 2 : In order not to use floating point numbers,
the coordinates of the points are integers numbers.
The displayed distance represents the square of the distance between 2 points */
/* This program draws heavily from the published C program. Thanks to its creator. */
/* for constantes see task include a file in arm assembly */
/************************************/
/* Constantes */
/************************************/
.include "../constantes.inc"
 
.equ MAXI, 3
.equ NBPOINTSRAND, 2000
.equ MAXCOORD, 10000
 
/***********************************************/
/* structures */
/**********************************************/
/* Définition node */
.struct 0
nodeKD_val: // value array
.struct nodeKD_val + (4 * MAXI)
nodeKD_left: // left pointer
.struct nodeKD_left + 4
nodeKD_right: // right pointer
.struct nodeKD_right + 4
nodeKD_end:
/*********************************/
/* Initialized data */
/*********************************/
.data
szMessAddressTree: .asciz "Node address : "
szMessTreeValue: .asciz " Value : "
szMessLeft: .asciz " Left : "
szMessRight: .asciz "Right : "
szMessResult: .asciz "Nearest point = "
szMessRandCoor: .asciz "\n\nRandom point coordonnés = "
szMessVisited: .asciz "Node visited = "
szMessDistance: .asciz "square distance :"
szMessStart: .asciz "Program 32 bits start.\n"
szCarriageReturn: .asciz "\n"
.align 4
tabPoint1: .int 2,3, 5,4, 9,6, 4,7, 8,1, 7,2
//tabPoint1: .int 1,7, 3,4, 4,6, 6,2, 8,12, 10,9, 12,3, 14,1
//tabPoint1: .int 3,5, 1,3, 2,8, 4,6, 5,4
.equ NBPOINTS, (. - tabPoint1) / 4
 
tabPoint2: .int 9,2
//tabPoint2: .int 3,7
.equ NBPOINTS2, (. - tabPoint2) / 4
iGraine: .int 123456 // random init
 
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
stNode1: .skip nodeKD_end
KDtree1: .skip nodeKD_end * NBPOINTS
KDtree2: .skip nodeKD_end * NBPOINTS2
KdtreeRand: .skip nodeKD_end * NBPOINTSRAND
tabPointsRand: .skip nodeKD_end
sZoneConv: .skip 24 // conversion buffer
sZoneConv1: .skip 24 // conversion buffer
sBufferConv16: .skip 16
iDistance: .skip 4 // best distance
stNearest: .skip nodeKD_end // best node
nbNodeVi: .skip 4 // visited node
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: @ entry of program
ldr r0,iAdrszMessStart
bl affichageMess
ldr r0,iAdrtabPoint1 @ points array address
ldr r1,iAdrKDtree1 @ KD tree address
mov r2,#NBPOINTS @ array points size
mov r3,#2 @ domension 2
bl initKDTree @ init tree
ldr r0,iAdrKDtree1 @ KD tree address
mov r1,#0 @ start index
mov r2,#NBPOINTS / 2 @ end = array points size
mov r3,#0 @ level
mov r4,#2 @ dimension 2
bl createTree
mov r8,r0 @ save median
cmp r0,#-1
beq 100f
ldr r0,iAdrKDtree1 @ KD tree address
mov r1,#2 @ dimension 2
bl displayTree
ldr r0,iAdrtabPoint2 @ points array address
ldr r1,iAdrKDtree2 @ search KDtree address
mov r2,#NBPOINTS2 @ search array points size
mov r3,#2 @ dimension 2
bl initKDTree @ init search tree
ldr r0,iAdrKDtree1 @ KDtree address
mov r1,#nodeKD_end
mla r0,r8,r1,r0 @ compute median address
ldr r1,iAdrKDtree2 @ search KDtree address
mov r2,#0 @ first index
mov r3,#2 @ dimension 2
bl searchNearest @ search nearest point
ldr r0,iAdrszMessResult @ display résult
bl affichageMess
ldr r0,iAdrstNearest @ nearest point address
ldr r0,[r0]
mov r1,#2
bl displayCoord @ coordonnés display
ldr r0,iAdrnbNodeVi @ visited nodes
ldr r0,[r0]
ldr r1,iAdrsZoneConv
bl conversion10
mov r0,#3
ldr r1,iAdrszMessVisited
ldr r2,iAdrsZoneConv
ldr r3,iAdrszCarriageReturn
bl displayStrings
ldr r0,iAdriDistance @ best distance address
ldr r0,[r0]
ldr r1,iAdrsZoneConv
bl conversion10
mov r0,#3
ldr r1,iAdrszMessDistance
ldr r2,iAdrsZoneConv
ldr r3,iAdrszCarriageReturn
bl displayStrings
bl traitRandom
100: @ standard end of the program
mov r0, #0 @ return code
mov r7, #EXIT @ request to exit program
svc #0 @ perform the system call
iAdrszCarriageReturn: .int szCarriageReturn
iAdrsZoneConv: .int sZoneConv
iAdrszMessDistance: .int szMessDistance
iAdrszMessResult: .int szMessResult
iAdrszMessVisited: .int szMessVisited
iAdrszMessStart: .int szMessStart
iAdrtabPoint1: .int tabPoint1
iAdrtabPoint2: .int tabPoint2
iAdrKDtree1: .int KDtree1
iAdrKDtree2: .int KDtree2
/***************************************************/
/* traitement random points */
/***************************************************/
traitRandom:
push {r1-r10,lr} @ save des registres
ldr r8,iAdrKdtreeRand @ KD tree address
mov r7,#nodeKD_end
ldr r10,iNbPointsRand
mov r3,#0
1: @ loop generate random coordonnes
mov r0,#MAXCOORD
bl genereraleas @ X
mov r4,r0
mov r0,#MAXCOORD
bl genereraleas @ Y
mov r5,r0
mov r0,#MAXCOORD
bl genereraleas @ Z
mov r6,r0
mla r0,r3,r7,r8
add r1,r0,#nodeKD_val @ node address
str r4,[r1] @ store X,Y,Z
str r5,[r1,#4]
str r6,[r1,#8]
mov r4,#-1 @ init pointer left and right
str r4,[r0,#nodeKD_left]
str r4,[r0,#nodeKD_right]
add r3,r3,#1
cmp r3,r10
blt 1b
mov r0,r8 @ KD tree address
mov r1,#0 @ start indice
mov r2,r10 @ array points size
mov r3,#0 @ level
mov r4,#3 @ dimension 2
bl createTree
mov r9,r0 @ save median
@ create random search point
mov r0,#MAXCOORD
bl genereraleas
mov r4,r0
mov r0,#MAXCOORD
bl genereraleas
mov r5,r0
mov r0,#MAXCOORD
bl genereraleas
mov r6,r0
ldr r3,iAdrtabPointsRand
add r0,r3,#nodeKD_val
str r4,[r0]
str r5,[r0,#4]
str r6,[r0,#8]
ldr r0,iAdrszMessRandCoor
bl affichageMess
mov r0,r3
mov r1,#3
bl displayCoord @ search
ldr r0,iAdriDistance @ init best distance address
mov r1,#0
str r1,[r0]
mla r0,r9,r7,r8 @ median KD tree address
mov r1,r3 @ search point address
mov r2,#0 @ index
mov r3,#3 @ dimension 2
bl searchNearest
ldr r0,iAdrszMessResult
bl affichageMess
ldr r0,iAdrstNearest
ldr r0,[r0]
mov r1,#3
bl displayCoord
ldr r0,iAdrnbNodeVi
ldr r0,[r0]
ldr r1,iAdrsZoneConv
bl conversion10
mov r0,#3
ldr r1,iAdrszMessVisited
ldr r2,iAdrsZoneConv
ldr r3,iAdrszCarriageReturn
bl displayStrings
ldr r0,iAdriDistance @ best distance address
ldr r0,[r0]
ldr r1,iAdrsZoneConv
bl conversion10
mov r0,#3
ldr r1,iAdrszMessDistance
ldr r2,iAdrsZoneConv
ldr r3,iAdrszCarriageReturn
bl displayStrings
100:
pop {r1-r10,pc}
iAdrKdtreeRand: .int KdtreeRand
iAdrtabPointsRand: .int tabPointsRand
iAdrszMessRandCoor: .int szMessRandCoor
iNbPointsRand: .int NBPOINTSRAND
/***************************************************/
/* init KN tree */
/***************************************************/
/* r0 array points */
/* r1 array tree address */
/* r2 points number */
/* r3 dimension */
initKDTree:
push {r1-r9,lr} @ save des registres
mov r8,#0 @ points indice
mov r4,#0 @ node tree indice
mov r6,#nodeKD_end @ structure size
1:
mla r5,r4,r6,r1 @ compute node address
mov r9,#0 @ index value
2:
ldr r7,[r0,r8,lsl #2] @ load one point coord
str r7,[r5,r9,lsl #2] @ store in node value
add r8,r8,#1 @ next point
add r9,r9,#1 @ next node value
cmp r9,r3 @ = dimension ?
blt 2b @ no loop
mov r7,#-1 @ init pointer left and right
str r7,[r5,#nodeKD_left]
str r7,[r5,#nodeKD_right]
add r4,r4,#1 @ increment node tree indice
cmp r8,r2 @ end points ?
blt 1b
100:
pop {r1-r9,pc}
/***************************************************/
/* create KD tree */
/***************************************************/
/* r0 array tree address */
/* r1 start index */
/* r2 end index
/* r3 level */
/* r4 dimention */
createTree:
push {r1-r12,lr} @ save des registres
cmp r1,r2 @ if start = end -> return -1
movge r0,#-1
bge 100f
add r5,r1,#1 @ if start + 1 = end -> return start
cmp r5,r2
moveq r0,r1
beq 100f
mov r8,r0 @ save address
mov r7,r1 @ save start index
mov r12,r2 @ save end index
mov r5,r3 @ save level
mov r10,r4 @ save dimension
mov r9,#nodeKD_end @ node structure size
mov r1,r7 @ start
mov r2,r12 @ end
bl findMedian
cmp r0,#0 @
movlt r0,#-1
blt 100f
mov r6,r0 @ save indice median
add r5,r5,#1 @ compute new value index
cmp r5,r10 @ => dimension ?
movge r5,#0
mov r0,r8 @ tree address
mov r1,r7 @ start
mov r2,r6 @ end = median
mov r3,r5 @ index
mov r4,r10 @ dimension
bl createTree
mla r1,r6,r9,r8 @ compute median address
cmp r0,#-1 @ left address is ok ?
mlane r0,r9,r0,r8 @ yes compute address
str r0,[r1,#nodeKD_left] @ and store
mov r0,r8 @ KDtree address
add r1,r6,#1 @ start = indice median + 1
mov r2,r12 @ end
mov r3,r5 @ index
mov r4,r10 @ dimension
bl createTree
mla r1,r6,r9,r8 @ compute median address
cmp r0,#-1 @ indice right ok ?
mlane r0,r9,r0,r8 @ yes compute address
str r0,[r1,#nodeKD_right] @ and store in pointer
mov r0,r6 @ return indice median node
100:
pop {r1-r12,pc}
/***************************************************/
/* find median and sort points */
/***************************************************/
/* r0 tree address */
/* r1 start tree indice
/* r2 end tree indice */
/* r3 indice */
/* r0 return median point index */
findMedian:
push {r1-r12,lr} @ save des registres
cmp r2,r1
movle r0,#-1
ble 100f
mov r7,#nodeKD_end @ node size
add r5,r1,#1 @ next node address
cmp r2,r5 @ equal to end ?
moveq r0,r1
beq 100f @ yes return
mov r8,r1 @ save start
mov r12,r0 @ save tree address
add r4,r2,r1 @ end + start
lsr r9,r4,#1 @ divide by 2 = median index
mla r10,r7,r9,r0 @ mediam md address
lsl r5,r3,#2 @ index * 4
1:
cmp r2,r8 @ end <= start
movle r0,r2 @ stop ?
ble 100f
add r6,r10,#nodeKD_val
add r11,r6,r5 @ add shift index
ldr r6,[r11] @ load pivot value
mov r0,r10 @ median address
sub r1,r2,#1 @ compute address end - 1
mul r1,r7,r1
add r1,r1,r12
bl inversion @ inversion median and end - 1
mov r11,r8 @ store=indice start
mov r4,r8 @ p =indice start
2:
cmp r4,r2 @ compare p and end
bge 5f
mla r3,r4,r7,r12 @ compute p address
add r3,r3,r5 @ add shift index
ldr r0,[r3] @ load value
cmp r0,r6 @ compare to pivot
bge 4f
cmp r4,r11 @ compare p et store
beq 3f
mla r0,r4,r7,r12 @ compute p address
mla r1,r11,r7,r12 @ compute store address
bl inversion @ inversion p and store
3:
add r11,r11,#1 @ increment store
4:
add r4,r4,#1 @ increment p
b 2b
5:
moveq r0,r9 @ equal return median index
beq 100f
mla r0,r11,r7,r12 @ store address
sub r1,r2,#1 @ end - 1
mla r1,r7,r1,r12 @ compute address
bl inversion @ inversion store and end - 1
ldr r0,[r0,#nodeKD_val] @ load store value
add r0,r0,r5 @ add shift index
ldr r1,[r10,#nodeKD_val] @ load median value
add r1,r1,r5 @ add shift index
cmp r0,r1 @ compare values
moveq r0,r9 @ equal return median index
beq 100f
cmp r11,r9 @ compare index store and median
movgt r2,r11 @ new end
movle r8,r11 @ new start
b 1b @ and loop
 
100:
pop {r1-r12,pc}
/***************************************************/
/* compute distance into 2 points */
/***************************************************/
/* r0 tree node address */
/* r1 search points address */
/* r2 dimension */
distance:
push {r3-r7,lr} @ save des registres
add r0,#nodeKD_val @ root node values array address
add r1,#nodeKD_val @ search node values array addresse
mov r3,#0 @ first value index
mov r7,#0 @ init distance
1:
ldr r4,[r0,r3,lsl #2] @ load value
ldr r5,[r1,r3,lsl #2] @ load value
sub r6,r5,r4 @ différence
add r3,r3,#1
mla r7,r6,r6,r7 @ compute square TODO: overflow
cmp r3,r2 @ end ?
blt 1b @ no -> loop
mov r0,r7 @ return distance
100:
pop {r3-r7,pc}
/***************************************************/
/* search nearest point */
/***************************************************/
/* r0 tree address */
/* r1 search points address */
/* r2 index */
/* r3 dimension */
searchNearest:
push {r1-r12,lr} @ save des registres
cmp r0,#-1
beq 100f
mov r7,r0 @ start with median
mov r8,r1 @ save serach point address
lsl r9,r2,#2 @ shift index
mov r10,r3 @ save dimension
mov r2,r3 @ dimension
bl distance @ compute distance
mov r11,r0
ldr r1,[r7,r9]
ldr r12,[r8,r9]
sub r12,r1
mul r6,r12,r12 @ distance axis
ldr r4,iAdriDistance
ldr r5,[r4]
cmp r5,#0 @ first distance ?
moveq r5,r11 @ new best distance
moveq r3,r7 @ new best node
beq 1f
cmp r11,r5 @ compare new distance and best distance
bgt 2f
mov r5,r11 @ new best distance
mov r3,r7 @ new best node
1:
str r5,[r4] @ store new best distance
ldr r4,iAdrstNearest @ and store best node address
str r3,[r4]
2:
ldr r1,iAdrnbNodeVi @ increment visited node
ldr r3,[r1]
add r3,r3,#1
str r3,[r1]
cmp r5,#0 @ distance = 0 -> end @
beq 100f
cmp r12,#0 @ else search in childen tree
ldrlt r0,[r7,#nodeKD_left]
ldrge r0,[r7,#nodeKD_right]
mov r1,r8
lsr r2,r9,#2
add r2,r2,#1
cmp r2,r10
movge r2,#0
mov r3,r10
bl searchNearest
ldr r4,iAdriDistance @ best distance
ldr r5,[r4]
cmp r6,r5 @ compare distance
bge 100f
cmp r12,#0 @ else search in childen tree
ldrge r0,[r7,#nodeKD_left]
ldrlt r0,[r7,#nodeKD_right]
bl searchNearest
100:
pop {r1-r12,pc}
iAdrstNearest: .int stNearest
iAdriDistance: .int iDistance
iAdrnbNodeVi: .int nbNodeVi
/***************************************************/
/* inversion */
/***************************************************/
/* r0 tree address */
/* r1 tree */
inversion:
push {r0-r4,lr} @ save des registres
add r0,#nodeKD_val
add r1,#nodeKD_val
mov r2,#0
1:
ldr r4,[r0,r2,lsl #2]
ldr r3,[r1,r2,lsl #2]
str r3,[r0,r2,lsl #2]
str r4,[r1,r2,lsl #2]
add r2,r2,#1
cmp r2,#MAXI
blt 1b
100:
pop {r0-r4,pc}
/***************************************************/
/* display tree */
/***************************************************/
/* r0 tree address */
/* r1 dimension */
displayTree:
push {r2-r12,lr} @ save des registres
mov r10,r0
mov r7,r1
mov r11,#0
mov r12,#nodeKD_end
1:
mla r9,r12,r11,r10
mov r0,r9
ldr r1,iAdrsBufferConv16
bl conversion16
mov r0,#2
ldr r1,iAdrszMessAddressTree
ldr r2,iAdrsBufferConv16
bl displayStrings
mov r8,#0
2:
add r4,r9,#nodeKD_val
ldr r0,[r4,r8,lsl #2]
ldr r1,iAdrsZoneConv
bl conversion10
mov r0,#2
ldr r1,iAdrszMessTreeValue
ldr r2,iAdrsZoneConv
bl displayStrings
add r8,r8,#1
cmp r8,r7
blt 2b
ldr r0,iAdrszCarriageReturn
bl affichageMess
add r0,r9,#nodeKD_left
ldr r0,[r0]
ldr r1,iAdrsZoneConv
bl conversion16
add r0,r9,#nodeKD_right
ldr r0,[r0]
ldr r1,iAdrsZoneConv1
bl conversion16
mov r0,#5
ldr r1,iAdrszMessLeft
ldr r2,iAdrsZoneConv
ldr r3,iAdrszMessRight
ldr r4,iAdrsZoneConv1
push {r4}
ldr r4,iAdrszCarriageReturn
push {r4}
bl displayStrings
add sp,sp,#8
add r11,r11,#1
cmp r11,#NBPOINTS / 2
blt 1b
100:
pop {r2-r12,pc}
iAdrszMessAddressTree: .int szMessAddressTree
iAdrszMessTreeValue: .int szMessTreeValue
iAdrsBufferConv16: .int sBufferConv16
iAdrszMessLeft: .int szMessLeft
iAdrszMessRight: .int szMessRight
iAdrsZoneConv1: .int sZoneConv1
/***************************************************/
/* display node coordonnées */
/***************************************************/
/* r0 node address */
/* r1 dimension */
displayCoord:
push {r1-r5,lr} @ save des registres
add r4,r0,#nodeKD_val
mov r3,r1 @ save dimension
mov r5,#0
1:
ldr r0,[r4,r5,lsl #2]
ldr r1,iAdrsZoneConv
bl conversion10
mov r0,#2
ldr r1,iAdrszMessTreeValue
ldr r2,iAdrsZoneConv
bl displayStrings
add r5,r5,#1
cmp r5,r3
blt 1b
ldr r0,iAdrszCarriageReturn
bl affichageMess
100:
pop {r1-r5,pc}
/***************************************************/
/* display multi strings */
/***************************************************/
/* r0 contains number strings address */
/* r1 address string1 */
/* r2 address string2 */
/* r3 address string3 */
/* other address on the stack */
/* thinck to add number other address * 4 to add to the stack */
displayStrings: @ INFO: displayStrings
push {r1-r4,fp,lr} @ save des registres
add fp,sp,#24 @ save paraméters address (6 registers saved * 4 bytes)
mov r4,r0 @ save strings number
cmp r4,#0 @ 0 string -> end
ble 100f
mov r0,r1 @ string 1
bl affichageMess
cmp r4,#1 @ number > 1
ble 100f
mov r0,r2
bl affichageMess
cmp r4,#2
ble 100f
mov r0,r3
bl affichageMess
cmp r4,#3
ble 100f
mov r3,#3
sub r2,r4,#4
1: @ loop extract address string on stack
ldr r0,[fp,r2,lsl #2]
bl affichageMess
subs r2,#1
bge 1b
100:
pop {r1-r4,fp,pc}
/***************************************************/
/* Generation random number */
/***************************************************/
/* r0 contains limit */
genereraleas:
push {r1-r4,lr} @ save registers
ldr r4,iAdriGraine
ldr r2,[r4]
ldr r3,iNbDep1
mul r2,r3,r2
ldr r3,iNbDep1
add r2,r2,r3
str r2,[r4] @ maj de la graine pour l appel suivant
cmp r0,#0
beq 100f
mov r1,r0 @ divisor
mov r0,r2 @ dividende
bl division
mov r0,r3 @ résult = remainder
100: @ end function
pop {r1-r4,lr} @ restaur registers
bx lr @ return
iAdriGraine: .int iGraine
iNbDep1: .int 0x343FD
iNbDep2: .int 0x269EC3
 
/***************************************************/
/* ROUTINES INCLUDE */
/***************************************************/
.include "../affichage.inc"
 
 
</syntaxhighlight>
{{Out}}
<pre>
Program 32 bits start.
Node address : 00012494 Value : 2 Value : 3
Left : FFFFFFFF Right : FFFFFFFF
Node address : 000124A8 Value : 9 Value : 6
Left : 00012494 Right : 000124BC
Node address : 000124BC Value : 5 Value : 4
Left : FFFFFFFF Right : FFFFFFFF
Node address : 000124D0 Value : 7 Value : 2
Left : 000124A8 Right : 000124F8
Node address : 000124E4 Value : 8 Value : 1
Left : FFFFFFFF Right : FFFFFFFF
Node address : 000124F8 Value : 4 Value : 7
Left : 000124E4 Right : FFFFFFFF
Nearest point = Value : 8 Value : 1
Node visited = 3
square distance :2
 
 
Random point coordonnés = Value : 4877 Value : 3830 Value : 3035
Nearest point = Value : 4947 Value : 4836 Value : 2401
Node visited = 122
square distance :1418892
</pre>
 
=={{header|C}}==
Using a Quickselectesque median algorithm. Compared to unbalanced trees (random insertion), it takes slightly longer (maybe half a second or so) to construct a million-node tree, though average look up visits about 1/3 fewer nodes.
<syntaxhighlight lang="c">
<lang c>
 
#include <stdio.h>
Line 207 ⟶ 1,760:
}
 
</syntaxhighlight>
</lang>
{{out}}
<pre>>> WP tree
Line 225 ⟶ 1,778:
=={{header|C++}}==
This code is based on the C version. A significant difference is the use of the standard library function nth_element, which replaces the find_median function in the C version.
<langsyntaxhighlight lang="cpp">#include <algorithm>
#include <array>
#include <cmath>
Line 321 ⟶ 1,874:
return nullptr;
size_t n = begin + (end - begin)/2;
std::nth_element(&nodes_[begin],auto &nodes_[n],i = &nodes_[0] + end, node_cmp.begin(index));
std::nth_element(i + begin, i + n, i + end, node_cmp(index));
index = (index + 1) % dimensions;
nodes_[n].left_ = make_tree(begin, n, index);
Line 373 ⟶ 1,927:
nodes_.reserve(n);
for (size_t i = 0; i < n; ++i)
nodes_.emplace_backpush_back(f());
root_ = make_tree(0, nodes_.size(), 0);
}
Line 469 ⟶ 2,023:
}
return 0;
}</langsyntaxhighlight>
 
{{out}}
Line 493 ⟶ 2,047:
=={{header|Common Lisp}}==
The 3D data set is the set of coordinates from (0,0,0) to (9,9,9) (ie. uniformly distributed), while the ordinates of the random target are positive real < 10.
<langsyntaxhighlight lang="lisp">
(in-package cl-user)
(defun main ()
(let ((dims 0) (target nil) (hits 0))
;;; distance node to target:
;;; returns squared euclidean distance, or squared semi distance if option set
(defun distance (n &optional (semi nil))
(if semi (expt (- (nth (first n) (second n)) (nth (first n) target)) 2)
(reduce #'+ (mapcar (lambda (x y) (* (- x y) (- x y))) (second n) target))))
 
(defvar *random-target*
;;; returns true if target is to its left in axis dim
(list (float (/ (random 1000) 100))
(defun target< (n)
(< (nth (first n) target)float (nth/ (firstrandom n1000) (second n100))))
(float (/ (random 1000) 100))))
 
(defun distance (n target &key (semi nil))
;;; return the next child when nn searching, return opposing child if option oppose set
"distance node to target:
(defun next-node (n &optional (oppose nil))
returns squared euclidean distance, or squared semi distance if option set"
(if (or (and (target< n) (not oppose)) (and (not (target< n)) oppose)) (third n) (fourth n)))
(if semi
(expt (- (nth (first n) (second n))
(nth (first n) target))
2)
(reduce #'+
(mapcar (lambda (x y) (* (- x y) (- x y)))
(second n)
target))))
 
(defun target< (n target)
;;; a kdtree is a binary tree where nodes are:
"returns true if target is to its left in axis dim"
;;; terminal: (axis data-point), or
(< (nth (first n) target)
;;; branch: (axis split-point (left-kdtree) (right-kdtree))
(defunnth make-kdtree(axisfirst datan) (second n))))
(if (null data) nil
(if (eql (length data) 1) ; singleton?
(list axis (first data)) ;; terminal node
;; else branch node:
;; #pts=odd splits list into 2 even parts with sp in middle
;; #pts=even splits list into 2 uneven parts with shorter length first (but never nil)
(let ((sd (sort (copy-list data) #'< :key (lambda (x) (nth axis x)))) ;; sort the axis ordinates
(sp (truncate (/ (length data) 2))) ;; get mid pt
(nxta (mod (1+ axis) dims)))
(list axis (nth sp sd) (make-kdtree nxta (subseq sd 0 sp)) (make-kdtree nxta (subseq sd (1+ sp))))))))
 
(defun next-node (n target &key (opposite nil))
;;; depth first visit all nodes in kdtree and optionally apply a function to each node visited
"return the next child when nn searching, return opposing child if option
(defun visit-kdtree (kdt &key (node-function null))
oppose set"
(when kdt
(if (or (and (target< n target) (not opposite))
(when node-function (funcall node-function kdt))
(visit-kdtreeand (thirdnot kdt)(target< :node-functionn node-functiontarget)) opposite))
(third n)
(visit-kdtree (fourth kdt) :node-function node-function)))
(fourth n)))
;;; count of the terminal nodes
(defun count-nodes (kdt)
(if kdt
(if (eql (length kdt) 2) 1
(+ 1 (count-nodes (third kdt)) (count-nodes (fourth kdt))))
0))
;;; nearest neighbour search
(defun nn-kdtree (kdt node-stack)
(when kdt
;; stage 1 - find the 'closest' terminal node using insertion logic
(let ((best (do ((node kdt (next-node node))) ((not (next-node node)) (incf hits) node) ;; return first best est.
(push node node-stack) (incf hits)))) ; iteration
;; stage 2 - unwind the path, at each node if node is closer then make it best
(do ((node (pop node-stack) (pop node-stack))) ((null node) best) ;; return nearest pt
;; iteration: update best if node is closer
(when (< (distance node) (distance best))
(setf best node))
 
(defun make-kdtree (axis data dims)
;; venture down opposing side if split point is inside HS
"a kdtree is a binary tree where nodes are:
(let ((opposing-best
terminal: (axis data-point), or
(if (< (distance node 'semi) (distance best)) ; use semi dist here
branch: (axis split-point (nnleft-kdtree) (nextright-node node 'opposite) (listkdtree))"
(cond ((null data) nil)
nil))) ;; otherwise ignore this subtree
((eql (length data) 1) ; singleton?
(list axis (first data))) ; terminal node
(when (and opposing-best (< (distance opposing-best) (distance best)))
;; else branch node:
(setf best opposing-best)))))))
;; #pts=odd splits list into 2 even parts with sp in middle
;; #pts=even splits list into 2 uneven parts with shorter length first (but never nil)
(t
(let ((sd (sort (copy-list data)
#'<
:key (lambda (x) (nth axis x)))) ; sort the axis ordinates
(sp (truncate (length data) 2)) ; get mid pt
(nxta (mod (1+ axis) dims)))
(list axis
(nth sp sd)
(make-kdtree nxta
(subseq sd 0 sp)
dims)
(make-kdtree nxta
(subseq sd (1+ sp))
dims))))))
 
(defun visit-kdtree (kdt &key (node-function nil))
;;; process one set of data & optionally display tree
"depth first visit all nodes in kdtree and optionally apply a function to
(defun process (data tgt &optional (render nil))
each node visited"
(setf target tgt)
(when kdt
(setf dims (length target))
(when node-function (funcall node-function kdt))
(setf hits 0)
(let* ((kdt (makevisit-kdtree 0(third data)kdt) (nn:node-function (nnnode-kdtree kdt (list)))function)
(visit-kdtree (fourth kdt) :node-function node-function)))
(when render
 
(visit-kdtree kdt
(defun count-nodes (kdt)
:node-function (lambda (n)
"count of the terminal nodes"
(format t "~A node: axis:~A point: ~A target:~A semi-distance-sqd:~A euclidean-distance-sqd:~A~%"
(cond ((null kdt) 0)
(if (not (next-node n)) "TERMINAL" "BRANCH") (first n) (second n)
((= (length kdt) 2) 1)
target (distance n 'semi) (distance n)))))
(t (+ 1
(format t "~%NN to ~A is ~A, distance ~A [tree has ~A nodes, ~A were visited.]~%" target (second nn) (sqrt (distance nn)) (count-nodes kdt) hits)))
(count-nodes (third kdt))
(count-nodes (fourth kdt))))))
;; MAIN: TASK 1 - nn search small set of 2D points
 
(process '((2 3) (5 4) (9 6) (4 7) (8 1) (7 2)) '(9 2) 'render)
(defvar *hits*)
 
;; TASK 2 - nn search 1000 coordinate points in 3D space
(defun nn-kdtree (kdt node-stack target)
(process
"nearest neighbour search"
(progn (let ((ll (list))) (dotimes (i 10) (dotimes (j 10) (dotimes (k 10) (push (list i j k) ll)))) ll))
(when kdt
(list (float (/ (random 1000) 100)) (float (/ (random 1000) 100)) (float (/ (random 1000) 100))))))
;; stage 1 - find the 'closest' terminal node using insertion logic
(let ((best (do ((node kdt (next-node node target)))
((not (next-node node target))
(incf *hits*)
node) ; return first best est.
(push node node-stack)
(incf *hits*))))
;; stage 2 - unwind the path, at each node if node is closer then make it best
(do ((node (pop node-stack) (pop node-stack)))
((null node) best) ; return nearest pt
;; iteration: update best if node is closer
(when (< (distance node target) (distance best target))
(setf best node))
;; venture down opposing side if split point is inside HS
(let ((opposing-best
(if (< (distance node target :semi t) (distance best target))
(nn-kdtree (next-node node target :opposite t)
(list)
target)
nil))) ; otherwise ignore this subtree
(when (and opposing-best
(< (distance opposing-best target) (distance best target)))
(setf best opposing-best)))))))
 
(defun process (data target
&key (render nil)
&aux (dims (length target)))
"process one set of data & optionally display tree"
(let* ((*hits* 0)
(kdt (make-kdtree 0 data dims))
(nn (nn-kdtree kdt (list) target)))
(when render
(visit-kdtree kdt
:node-function
(lambda (n)
(format t
"~A node: axis:~A point: ~A target:~A semi-distance-sqd:~A euclidean-distance-sqd:~A~%"
(if (not (next-node n target))
"TERMINAL"
"BRANCH")
(first n)
(second n)
target
(distance n target :semi t)
(distance n target)))))
(format t "~%NN to ~A is ~A, distance ~A [tree has ~A nodes, ~A were visited.]~%"
target
(second nn)
(sqrt (distance nn target))
(count-nodes kdt)
*hits*)))
 
(defun main ()
;; TASK 1 - nn search small set of 2D points
(process '((2 3) (5 4) (9 6) (4 7) (8 1) (7 2))
'(9 2)
:render t)
 
;; TASK 2 - nn search 1000 coordinate points in 3D space
(process (let ((ll (list)))
(dotimes (i 10)
(dotimes (j 10)
(dotimes (k 10)
(push (list i j k) ll))))
ll)
*random-target*))
 
</syntaxhighlight>
</lang>
 
{{out}}
Line 606 ⟶ 2,215:
{{trans|Go}}
Points are values, the code is templated on the the dimensionality of the points and the floating point type of the coordinate. Instead of sorting it uses the faster topN, that partitions the points array in two halves around their median.
<langsyntaxhighlight lang="d">// Implmentation following pseudocode from
// "An introductory tutorial on kd-trees" by Andrew W. Moore,
// Carnegie Mellon University, PDF accessed from:
Line 814 ⟶ 2,423:
writefln("Visited an average of %0.2f nodes on %d searches " ~
"in %d ms.", visited / double(M), M, sw.peek.msecs);
}</langsyntaxhighlight>
{{out|Output}} using the ldc2 compiler
<pre>Wikipedia example data:
Line 833 ⟶ 2,442:
{{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.
<langsyntaxhighlight lang="d">import std.stdio, std.algorithm, std.math, std.random;
 
struct KdNode(size_t dim) {
Line 991 ⟶ 2,600:
sum, testRuns, sum / double(testRuns));
}
</syntaxhighlight>
</lang>
{{out}}
<pre>WP tree:
Line 1,007 ⟶ 2,616:
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">// Implmentation following pseudocode from "An intoductory tutorial on kd-trees"
// by Andrew W. Moore, Carnegie Mellon University, PDF accessed from
// http://www.autonlab.org/autonweb/14665
Line 1,189 ⟶ 2,798:
fmt.Println("distance: ", math.Sqrt(ssq))
fmt.Println("nodes visited: ", nv)
}</langsyntaxhighlight>
{{out}}
<pre>
Line 1,207 ⟶ 2,816:
=={{header|Haskell}}==
There is a space leak when creating the trees which will lead to terrible performance on massive trees. This can probably be quelled with strictness annotations.
<langsyntaxhighlight Haskelllang="haskell">import System.Random
import Data.List (sortBy, genericLength, minimumBy)
import Data.Ord (comparing)
Line 1,407 ⟶ 3,016:
printResults randSearch randNearest tuple3D
putStrLn "Confirm naive nearest:"
print randNearestLinear</langsyntaxhighlight>
{{out}}
<pre>Wikipedia example:
Line 1,428 ⟶ 3,037:
As a general rule, tree algorithms are a bad idea in J. That said, here's an implementation:
 
<langsyntaxhighlight Jlang="j">coclass 'kdnode'
create=:3 :0
Axis=: ({:$y)|<.2^.#y
Line 1,496 ⟶ 3,105:
'dist point'=. nearest__root y
dist;N_base_;point
)</langsyntaxhighlight>
 
And here's example use:
 
<langsyntaxhighlight Jlang="j"> tree=:conew&'kdtree' (2,3), (5,4), (9,6), (4,7), (8,1),: (7,2)
nearest__tree 9 2
┌───────┬─┬───┐
│1.41421│4│8 1│
└───────┴─┴───┘</langsyntaxhighlight>
 
The first box is distance from argument point to selected point. The second box is the number of nodes visited. The third box is the selected point.
Line 1,510 ⟶ 3,119:
Here's the bigger problem:
 
<langsyntaxhighlight Jlang="j"> tree=:conew&'kdtree' dataset=:?1000 3$0
nearest__tree pnt
┌─────────┬──┬──────────────────────────┐
│0.0387914│12│0.978082 0.767632 0.392523│
└─────────┴──┴──────────────────────────┘</langsyntaxhighlight>
 
So, why are trees "generally a bad idea in J"?
Line 1,522 ⟶ 3,131:
Well, let's compare the above implementation to a brute force implementation for time. Here's a "visit all nodes" implementation. It should give us the same kinds of results but we will claim that each candidate point is a node so we'll be visiting a lot more "nodes":
 
<langsyntaxhighlight Jlang="j">build0=:3 :0
data=: y
)
Line 1,531 ⟶ 3,140:
nearest=. data {~ (i. <./) |data distance y
(nearest distance y);(#data);nearest
)</langsyntaxhighlight>
 
Here's the numbers we get:
 
<langsyntaxhighlight Jlang="j"> build0 (2,3), (5,4), (9,6), (4,7), (8,1),: (7,2)
nearest0 9 2
┌───────┬─┬───┐
Line 1,544 ⟶ 3,153:
┌─────────┬────┬──────────────────────────┐
│0.0387914│1000│0.978082 0.767632 0.392523│
└─────────┴────┴──────────────────────────┘</langsyntaxhighlight>
 
But what about timing?
 
<langsyntaxhighlight Jlang="j"> tree=:conew&'kdtree' (2,3), (5,4), (9,6), (4,7), (8,1),: (7,2)
timespacex 'nearest__tree 9 2'
0.000487181 19328
build0 (2,3), (5,4), (9,6), (4,7), (8,1),: (7,2)
timespacex 'nearest0 9 2'
3.62419e_5 6016</langsyntaxhighlight>
 
The kdtree implementation is over ten times slower than the brute force implementation for this small dataset. How about the bigger dataset?
 
<langsyntaxhighlight Jlang="j"> tree=:conew&'kdtree' dataset
timespacex 'nearest__tree pnt'
0.00141408 45312
build0 dataset
timespacex 'nearest0 pnt'
0.00140702 22144</langsyntaxhighlight>
 
On the bigger dataset, the kdtree implementation is about the same speed as the brute force implementation.
Line 1,573 ⟶ 3,182:
Based on the C++ solution.
File KdTree.java:
<langsyntaxhighlight lang="java">import java.util.*;
 
public class KdTree {
Line 1,682 ⟶ 3,291:
}
}
}</langsyntaxhighlight>
File QuickSelect.java:
<langsyntaxhighlight lang="java">import java.util.*;
 
//
Line 1,735 ⟶ 3,344:
return left + random.nextInt(right - left + 1);
}
}</langsyntaxhighlight>
File KdTreeTest.java:
<langsyntaxhighlight lang="java">import java.util.*;
 
public class KdTreeTest {
Line 1,784 ⟶ 3,393:
System.out.println("nodes visited: " + tree.visited());
}
}</langsyntaxhighlight>
 
{{out}}
Line 1,804 ⟶ 3,413:
distance: 0.004361560347252592
nodes visited: 34
</pre>
 
=={{header|jq}}==
{{Works with|jq}}
 
'''Works with gojq, the Go implementation of jq'''
 
'''Adapted from [[#Wren|Wren]] and [[#Kotlin]]'''
 
Since jq does not include a PRNG, the following assumes that
an external source of entropy such as /dev/urandom is available.
See the "Invocation" section below for details.
 
In the following, a Point is represented by a numeric JSON array.
<syntaxhighlight lang="jq">
### Generic utilities
# Output: a PRN in range(0; .)
def prn:
if . == 1 then 0
else . as $n
| (($n-1)|tostring|length) as $w
| [limit($w; inputs)] | join("") | tonumber
| if . < $n then . else ($n | prn) end
end;
 
def rand: 1000 | prn / 1000;
 
def randomPt($dim):
[ range(0; $dim) | rand ] ;
 
def randomPts($dim; $n):
[ range(0;$n) | randomPt($dim) ];
 
def sq: .*.;
 
# $p and $q should be numeric arrays of the same length
def PtSqd($p; $q):
[$p, $q] | transpose | map((.[0] - .[1]) | sq) | add;
 
 
### K-d trees
 
def HyperRect($min; $max):
{ $min, $max };
 
def NearestNeighbor($nearest; $distSqd; $nodesVisited):
{ $nearest, $distSqd, $nodesVisited };
def KdNode($domElt; $split; $left; $right):
{$domElt, $split, $left, $right};
 
def KdTree($pts; $bounds):
def nk2($exset; $split):
if ($exset|length == 0) then null
else { $exset }
| .exset |= sort_by(.[$split])
| .m = ((.exset|length/2)|floor)
| .exset[.m] as $d
| until (.m + 1 >= (.exset|length) or .exset[.m + 1][$split] != $d[$split];
.m += 1)
| .s2 = $split + 1
| if .s2 == ($d|length) then .s2 = 0 else . end
| KdNode($d;
$split;
nk2(.exset[: .m]; .s2);
nk2(.exset[.m + 1 :]; .s2)
)
end ;
{ n: nk2($pts; 0),
$bounds } ;
 
# Input: a KdTree
def nearest($p):
# Input: a KdTree
def nn_($target; $hr; $maxDistSqd):
if not then NearestNeighbor(null; infinite; 0)
else .split as $s
| .domElt as $pivot
| .left as $left
| .right as $right
| ($target[$s] <= $pivot[$s]) as $targetInLeft
| { nodesVisited: 1,
leftHr: $hr,
rightHr: $hr }
| .leftHr.max[$s] = $pivot[$s]
| .rightHr.min[$s] = $pivot[$s]
| (if $targetInLeft then $left else $right end) as $nearerKd
| (if $targetInLeft then .leftHr else .rightHr end) as $nearerHr
| (if $targetInLeft then $right else $left end) as $furtherKd
| (if $targetInLeft then .rightHr else .leftHr end) as $furtherHr
| ($nearerKd | nn_($target; $nearerHr; $maxDistSqd)) as $res
| .nearest = $res.nearest
| .distSqd = $res.distSqd
| .nodesVisited += $res.nodesVisited
| .maxDistSqd2 = ([.distSqd, $maxDistSqd] | min)
| .d = (($pivot[$s] - $target[$s]) | sq)
| if .d > .maxDistSqd2 then NearestNeighbor(.nearest; .distSqd; .nodesVisited)
else .d = PtSqd($pivot; $target)
| if .d < .distSqd
then .nearest = $pivot
| .distSqd = .d
| .maxDistSqd2 = .distSqd
else .
end
| ($furtherKd | nn_($target; $furtherHr; .maxDistSqd2)) as $temp
| .nodesVisited += $temp.nodesVisited
| if $temp.distSqd < .distSqd
then .nearest = $temp.nearest
| .distSqd = $temp.distSqd
else .
end
| NearestNeighbor(.nearest; .distSqd; .nodesVisited)
end
end ;
.n | nn_($p; .bounds; infinite);
 
def example($heading; $hr; $points; $p):
KdTree($points; .hr)
| nearest($p)
| "\(heading):",
"Point : \($p)",
"Nearest neighbor : \(.nearest)",
"Distance : \(.distSqd | sqrt)",
"Nodes visited : \(.nodesVisited)",
"";
 
### Examples
 
def points: [[2, 3], [5, 4], [9, 6], [4, 7], [8, 1], [7, 2]];
 
example("WP example data";
HyperRect([0, 0]; [10, 10]); points; [9,2] ),
 
example("1,000 random 3D points";
HyperRect([0, 0, 0]; [1, 1, 1]); randomPts(3; 1000); randomPt(3)),
 
example("400,000 random 3D points";
HyperRect([0, 0, 0]; [1, 1, 1]); randomPts(3; 400,000); randomPt(3))
</syntaxhighlight>
{{output}}
<pre>
WP example data:
Point : [9,2]
Nearest neighbor : [8,1]
Distance : 1.4142135623730951
Nodes visited : 3
 
1,000 random 3D points:
Point : [0.625,0.521,0.996]
Nearest neighbor : [0.597,0.492,0.997]
Distance : 0.040323690307311935
Nodes visited : 28
 
400,000 random 3D points:
Point : [0.847,0.237,0.702]
Nearest neighbor : [0.848,0.237,0.706]
Distance : 0.004123105625617665
Nodes visited : 29
</pre>
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia">ENV["NN_DEBUG"] = true # or change DEBUG = true in NearestNeighbors.jl file
 
using NearestNeighbors
Line 1,838 ⟶ 3,607:
" at distance $(dist[1]).")
NearestNeighbors.print_stats()
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 1,858 ⟶ 3,627:
=={{header|Kotlin}}==
{{trans|Go}}
<langsyntaxhighlight lang="scala">// version 1.1.51
 
import java.util.Random
Line 1,983 ⟶ 3,752:
kd = KdTree(randomPts(3, 400_000), hr)
showNearest("400,000 random 3D points", kd, randomPt(3))
}</langsyntaxhighlight>
 
Sample output:
Line 2,006 ⟶ 3,775:
</pre>
 
=={{header|PhixNim}}==
{{trans|CD}}
This Nim version is an adaptation of the D fast version which is a translation of the C version. And on some points our version is closer to the C++ version, also an adaptation of the C version.
Added the 3D cube of 1000 points (0,0,0 to 9,9,9), which was not present in the C code,
then inspired by the single "naughty global" of C (visited), I decided to outdo that as
well, and have four of them ;-). [With enough motivation, many functions would probably
accept more parameters and return multiple values instead.]
<lang Phix>enum X,LEFT,RIGHT -- (keeping the IDX on each node too would not be a bad idea..)
-- (the code below deduces it from the (unbalanced) tree depth)
 
We have tried to be as generic as possible, accepting nodes of any numerical type (and tested for integers and floats).
sequence kd_nodes -- nb probably not best coding style
function sqdist(sequence p,q)
atom dsq = sum(sq_power(sq_sub(p,q),2))
return dsq
end function
 
<syntaxhighlight lang="nim">type
procedure swap(integer x,y)
{kd_nodes[x],kd_nodes[y]} = {kd_nodes[y],kd_nodes[x]}
end procedure
function find_median(integer first, last, idx)
if last<=first then return NULL end if
if last==first+1 then return first end if
integer p, stor, md = first+floor((last-first)/2)
atom pivot
while true do
pivot = kd_nodes[md][X][idx]
swap(md, last-1)
stor = first
for p=first to last-1 do
if kd_nodes[p][X][idx]<pivot then
if p!=stor then
swap(p, stor)
end if
stor += 1
end if
end for
swap(stor, last-1)
/* median has duplicate values */
if kd_nodes[stor][X][idx] == kd_nodes[md][X][idx] then
return md
end if
if stor>md then last = stor else first = stor end if
end while
end function
function make_tree(object t, len, i, dim)
if sequence(t) then kd_nodes = t; t = 1; end if
if len=0 then return 0 end if
integer n = find_median(t, t+len, i)
if n then
i = mod(i,dim)+1
if length(kd_nodes[n])!=1 then ?9/0 end if -- (once)
kd_nodes[n] = {kd_nodes[n][X],0,0} -- (add l/r slots)
kd_nodes[n][LEFT] = make_tree(t, n-t, i, dim)
kd_nodes[n][RIGHT] = make_tree(n+1, t+len-(n+1), i, dim)
end if
return n
end function
integer visited,
best
atom best_dist
procedure nearest(integer root, sequence nd, integer i, dim)
if root=0 then return end if
atom d = sqdist(kd_nodes[root][X],nd[X]),
dx = kd_nodes[root][X][i] - nd[X][i],
dx2 = dx * dx;
visited += 1
if best=0 or d<best_dist then
best_dist = d;
best = root;
end if
/* if chance of exact match is high */
if best_dist=0 then return end if
 
Point[Dim: static Natural; T: SomeNumber] = array[Dim, T]
i = mod(i,dim)+1
integer {l,r} = kd_nodes[root][LEFT..RIGHT]
{l,r} = iff(dx>0?{l,r}:{r,l})
nearest(l, nd, i, dim)
if (dx2 >= best_dist) then return end if
nearest(r, nd, i, dim)
end procedure
function rand_pt() return sq_rnd({{0,0,0}}) end function
 
KdNode[Dim: static Natural; T: SomeNumber] = ref object
function make_3D()
sequencex: sPoint[Dim, = {}T]
forleft, i=0right: toKdNode[Dim, 9 doT]
for j=0 to 9 do
for k=0 to 9 do
s = append(s,{{i,j,k}})
end for
end for
end for
return s
end function
 
constant test_runs = 100_000
 
func toKdNodes[N, Dim: static Natural; T](a: array[N, array[Dim, T]]): array[N, KdNode[Dim, T]] =
procedure test(string id, sequence nodes, sequence test_node, bool show_average_behaviour=false)
## Create an array of KdNodes from an array of list of numerical values.
integer dim = length(nodes[1][X]),
for i in 0..<N:
root = make_tree(nodes, length(nodes), 1, dim)
result[i] = KdNode[Dim, T](x: a[i])
best = 0
visited = 0
nearest(root, test_node, 1, dim)
string tn = sprint(test_node[X]),
bn = sprint(kd_nodes[best][X])
printf(1,"\n>> %s tree\nsearching for %s\n"&
"found %s dist %g\nseen %d nodes\n",
{id, tn, bn, sqrt(best_dist), visited})
 
if show_average_behaviour then
--
-- search many random points to see average behavior.
--
-- tree size vs avg nodes visited:
-- 10 ~ 7
-- 100 ~ 16.5
-- 1000 ~ 25.5
-- 10000 ~ 32.8
-- 100000 ~ 38.3
-- 1000000 ~ 42.6
-- 10000000 ~ 46.7
--
int tot = 0
for i=1 to test_runs do
best = 0
visited = 0
test_node = rand_pt()
nearest(root, test_node, 1, 3)
tot += visited
end for
printf(1,"average behaviour: "&
"visited %d nodes for %,d random findings (%f per lookup)\n",
{tot, test_runs, tot/test_runs});
end if
end procedure
 
func dist(a, b: Point): Point.T =
sequence wp = {{{2, 3}}, {{5, 4}}, {{9, 6}}, {{4, 7}}, {{8, 1}}, {{7, 2}}},
## Return the squared distance between two points.
test_node = {{9, 2}}
for i in 0..<Point.Dim:
test("WP",wp,test_node)
let t = a[i] - b[i]
result += t * t
 
sequence cube = make_3D()
test_node = sq_mul(rand_pt(),10)
test("3D",cube,test_node,true)
 
func findMedian(nodes: openArray[KdNode]; slice: Slice; idx: Natural): int =
constant N = 1_000_000
## Return the index of the median node in a list of nodes.
sequence million = repeat(0,N)
## The list is defined by the full list of nodes and an slice.
for i=1 to N do million[i] = rand_pt() end for
 
test_node = rand_pt()
var first = slice.a
test("Million",million,test_node,true)</lang>
var last = slice.b
if last < first: return -1
if last == first: return first
 
let md = first + (last - first + 1) div 2
 
while true:
let pivot = nodes[md].x[idx]
 
swap nodes[md].x, nodes[last].x
var store = first
for i in first..last:
if nodes[i].x[idx] < pivot:
if i != store:
swap nodes[i].x, nodes[store].x
inc store
swap nodes[store].x, nodes[last].x
 
if nodes[store].x[idx] == nodes[md].x[idx]:
return md
 
if store > md:
last = store
else:
first = store
 
 
func makeTree(nodes: openArray[KdNode]; slice: Slice; idx: Natural = 0): KdNode =
## Build a tree from a list of nodes. Return the root of the tree.
 
if slice.b < slice.a: return nil
 
let n = nodes.findMedian(slice, idx)
if n < 0: return nil
 
let idx = (idx + 1) mod result.Dim
nodes[n].left = nodes.makeTree(slice.a..<n, idx)
nodes[n].right = nodes.makeTree((n + 1)..slice.b, idx)
result = nodes[n]
 
 
func nearest(root,: KdNode; point: Point; idx: Natural;
best: var KdNode; bestDist: var root.T; nVisited: var int) =
## Return the node of a tree which is the nearest to a given point.
 
if root.isNil: return
 
let d = dist(root.x, point)
let dx = root.x[idx] - point[idx]
inc nVisited
 
if best.isNil or d < bestDist:
bestDist = d
best = root
 
if bestDist == 0: return
 
let idx = (idx + 1) mod root.Dim
 
nearest(if dx > 0: root.left else: root.right, point, idx, best, bestDist, nVisited)
if dx * dx >= bestDist: return
nearest(if dx > 0: root.right else: root.left, point, idx, best, bestDist, nVisited)
 
 
#———————————————————————————————————————————————————————————————————————————————————————————————————
 
 
when isMainModule:
 
import math, random, strformat
 
 
proc displayResult(title: string; thisPt: Point;
found: KdNode; bestDist: thisPt.T; nVisited: int) =
echo title & ':'
echo &" Searching for {thisPt}"
echo &" Found {found.x}, dist = {sqrt(float(bestDist)):.5f}"
echo &" Seen {nVisited} nodes."
echo ""
 
 
proc initRandom(point: var Point) =
for item in point.mitems:
item = rand(1.0)
 
 
proc runSmallTest() =
 
let
wp = [[2, 3], [5, 4], [9, 6], [4, 7], [8, 1], [7, 2]].toKdNodes()
#thisPt = newPoint([9, 2])
thisPt = Point([9, 2])
root = wp.makeTree(0..wp.high)
 
var
found: KdNode[root.Dim, root.T]
bestDist = root.T(0)
nVisited = 0
 
root.nearest(thisPt, 0, found, bestDist, nVisited)
displayResult("WP tree", thisPt, found, bestDist, nVisited)
 
 
proc runBigTest() =
 
const N = 1_000_000
const TestRuns = 100_000
 
randomize()
 
var bigTree: array[N, KdNode[3, float]]
for node in bigTree.mitems:
new(node)
node.x.initRandom()
 
let root = bigTree.makeTree(0..bigTree.high)
var thisPt: Point[3, float]
thisPt.initRandom()
 
var
found: KdNode[3, float]
bestDist = 0.0
nVisited = 0
 
root.nearest(thisPt, 0, found, bestDist, nVisited)
displayResult("Big Tree", thisPt, found, bestDist, nVisited)
 
var sum = 0
for _ in 0..<TestRuns:
found = nil
nVisited = 0
thisPt.initRandom()
root.nearest(thisPt, 0, found, bestDist, nVisited)
sum += nVisited
 
echo "Big tree:"
echo &" Visited {sum} nodes for {TestRuns} random searches ({sum / TestRuns:.2f} per lookup)."
 
runSmallTest()
runBigTest()</syntaxhighlight>
 
{{out}}
<pre>WP tree:
Searching for [9, 2]
Found [8, 1], dist = 1.41421
Seen 3 nodes.
 
Big Tree:
Searching for [0.4851429304889259, 0.3418258981276956, 0.8257271960979238]
Found [0.4805897150826164, 0.3388812898131908, 0.8295219237899825], dist = 0.00662
Seen 47 nodes.
 
Big tree:
Visited 4271480 nodes for 100000 random searches (42.71 per lookup).</pre>
 
=={{header|Phix}}==
{{trans|C}}
Added the 3D cube of 1000 points (0,0,0 to 9,9,9), which was not present in the C code, then inspired by
the single "naughty global" of C (visited) I decided to outdo that as well, and have four of them ;-).
[With enough motivation, many functions would probably accept more parameters and return multiple values instead.]
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">-- demo\rosetta\kd_tree.exw</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">enum</span> <span style="color: #000000;">X</span><span style="color: #0000FF;">,</span><span style="color: #000000;">LEFT</span><span style="color: #0000FF;">,</span><span style="color: #000000;">RIGHT</span> <span style="color: #000080;font-style:italic;">-- (keeping the IDX on each node too would not be a bad idea..)
-- (the code below deduces it from the (unbalanced) tree depth)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">kd_nodes</span> <span style="color: #000080;font-style:italic;">-- nb probably not best coding style</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">sqdist</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">,</span><span style="color: #000000;">q</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">sum</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_power</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_sub</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">,</span><span style="color: #000000;">q</span><span style="color: #0000FF;">),</span><span style="color: #000000;">2</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">swap</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">)</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">kd_nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">],</span><span style="color: #000000;">kd_nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">kd_nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">],</span><span style="color: #000000;">kd_nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">find_median</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">first</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">last</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">idx</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">last</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">first</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #004600;">NULL</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">last</span><span style="color: #0000FF;">==</span><span style="color: #000000;">first</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">first</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">stor</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">md</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">first</span><span style="color: #0000FF;">+</span><span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">last</span><span style="color: #0000FF;">-</span><span style="color: #000000;">first</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">pivot</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">kd_nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">md</span><span style="color: #0000FF;">][</span><span style="color: #000000;">X</span><span style="color: #0000FF;">][</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">swap</span><span style="color: #0000FF;">(</span><span style="color: #000000;">md</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">last</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">stor</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">first</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">=</span><span style="color: #000000;">first</span> <span style="color: #008080;">to</span> <span style="color: #000000;">last</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">kd_nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">p</span><span style="color: #0000FF;">][</span><span style="color: #000000;">X</span><span style="color: #0000FF;">][</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">]<</span><span style="color: #000000;">pivot</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">stor</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">swap</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">stor</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">stor</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">swap</span><span style="color: #0000FF;">(</span><span style="color: #000000;">stor</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">last</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">/* median has duplicate values */</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">sx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">kd_nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">stor</span><span style="color: #0000FF;">][</span><span style="color: #000000;">X</span><span style="color: #0000FF;">][</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">],</span>
<span style="color: #000000;">mx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">kd_nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">md</span><span style="color: #0000FF;">][</span><span style="color: #000000;">X</span><span style="color: #0000FF;">][</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">sx</span> <span style="color: #0000FF;">==</span> <span style="color: #000000;">mx</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">stor</span><span style="color: #0000FF;">></span><span style="color: #000000;">md</span> <span style="color: #008080;">then</span> <span style="color: #000000;">last</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">stor</span> <span style="color: #008080;">else</span> <span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">stor</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">md</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">make_tree</span><span style="color: #0000FF;">(</span><span style="color: #004080;">object</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">len</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">dim</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #004080;">sequence</span><span style="color: #0000FF;">(</span><span style="color: #000000;">t</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">kd_nodes</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">t</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">t</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">len</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">?</span><span style="color: #000000;">0</span><span style="color: #0000FF;">:</span><span style="color: #000000;">find_median</span><span style="color: #0000FF;">(</span><span style="color: #000000;">t</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">+</span><span style="color: #000000;">len</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">n</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">i</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dim</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">1</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">kd_nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">])!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- (once)</span>
<span style="color: #000000;">kd_nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">kd_nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">][</span><span style="color: #000000;">X</span><span style="color: #0000FF;">],</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}</span> <span style="color: #000080;font-style:italic;">-- (add l/r slots)</span>
<span style="color: #000000;">kd_nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">][</span><span style="color: #000000;">LEFT</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">make_tree</span><span style="color: #0000FF;">(</span><span style="color: #000000;">t</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">-</span><span style="color: #000000;">t</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">dim</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">kd_nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">][</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">make_tree</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">+</span><span style="color: #000000;">len</span><span style="color: #0000FF;">-(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">dim</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">n</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">visited</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">best</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">best_dist</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">nearest</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">root</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">nd</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">dim</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">root</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">d</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">sqdist</span><span style="color: #0000FF;">(</span><span style="color: #000000;">kd_nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">][</span><span style="color: #000000;">X</span><span style="color: #0000FF;">],</span><span style="color: #000000;">nd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">]),</span>
<span style="color: #000000;">dx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">kd_nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">][</span><span style="color: #000000;">X</span><span style="color: #0000FF;">][</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">nd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">][</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span>
<span style="color: #000000;">dx2</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dx</span> <span style="color: #0000FF;">*</span> <span style="color: #000000;">dx</span><span style="color: #0000FF;">;</span>
<span style="color: #000000;">visited</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">best</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">or</span> <span style="color: #000000;">d</span><span style="color: #0000FF;"><</span><span style="color: #000000;">best_dist</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">best_dist</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">;</span>
<span style="color: #000000;">best</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">root</span><span style="color: #0000FF;">;</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000080;font-style:italic;">/* if chance of exact match is high */</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">best_dist</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">i</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dim</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">1</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,</span><span style="color: #000000;">r</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">kd_nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">][</span><span style="color: #000000;">LEFT</span><span style="color: #0000FF;">..</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">dx</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,</span><span style="color: #000000;">r</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">r</span><span style="color: #0000FF;">,</span><span style="color: #000000;">l</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">nearest</span><span style="color: #0000FF;">(</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">nd</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">dim</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">dx2</span> <span style="color: #0000FF;">>=</span> <span style="color: #000000;">best_dist</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">nearest</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">nd</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">dim</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">rand_pt</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">return</span> <span style="color: #7060A8;">sq_rnd</span><span style="color: #0000FF;">({{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}})</span> <span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">make_3D</span><span style="color: #0000FF;">()</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">to</span> <span style="color: #000000;">9</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">to</span> <span style="color: #000000;">9</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">to</span> <span style="color: #000000;">9</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,{{</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">j</span><span style="color: #0000FF;">,</span><span style="color: #000000;">k</span><span style="color: #0000FF;">}})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">s</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #000080;font-style:italic;">// aside: shave a little off under pwa/p2js, but 1e6 build still takes ~20s</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">test_runs</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()=</span><span style="color: #004600;">JS</span><span style="color: #0000FF;">?</span><span style="color: #000000;">10_000</span><span style="color: #0000FF;">:</span><span style="color: #000000;">100_000</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">id</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">nodes</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">test_node</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">bool</span> <span style="color: #000000;">show_average_behaviour</span><span style="color: #0000FF;">=</span><span style="color: #004600;">false</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">dim</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">X</span><span style="color: #0000FF;">]),</span>
<span style="color: #000000;">root</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">make_tree</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nodes</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nodes</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">dim</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">best</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #000000;">visited</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #000000;">nearest</span><span style="color: #0000FF;">(</span><span style="color: #000000;">root</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">test_node</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">dim</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n&gt;&gt; %s tree\nsearching for %v\nfound %v dist %g\nseen %d nodes\n"</span><span style="color: #0000FF;">,</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">id</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">test_node</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">kd_nodes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">best</span><span style="color: #0000FF;">][</span><span style="color: #000000;">X</span><span style="color: #0000FF;">],</span> <span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">best_dist</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">visited</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">show_average_behaviour</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">--
-- search many random points to see average behavior.
--
-- tree size vs avg nodes visited:
-- 10 ~ 7
-- 100 ~ 16.5
-- 1000 ~ 25.5
-- 10000 ~ 32.8
-- 100000 ~ 38.3
-- 1000000 ~ 42.6
-- 10000000 ~ 46.7
--</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">total</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">test_runs</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">best</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #000000;">visited</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #000000;">test_node</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rand_pt</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">nearest</span><span style="color: #0000FF;">(</span><span style="color: #000000;">root</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">test_node</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">total</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">visited</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"average behaviour: "</span><span style="color: #0000FF;">&</span>
<span style="color: #008000;">"visited %d nodes for %,d random findings (%f per lookup)\n"</span><span style="color: #0000FF;">,</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">total</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">test_runs</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">total</span><span style="color: #0000FF;">/</span><span style="color: #000000;">test_runs</span><span style="color: #0000FF;">});</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">wp</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{{</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">}},</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">}},</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">9</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6</span><span style="color: #0000FF;">}},</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7</span><span style="color: #0000FF;">}},</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">}},</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">}}},</span>
<span style="color: #000000;">test_node</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">9</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">}}</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"WP"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">wp</span><span style="color: #0000FF;">,</span><span style="color: #000000;">test_node</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">cube</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">make_3D</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">test_node</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sq_mul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rand_pt</span><span style="color: #0000FF;">(),</span><span style="color: #000000;">10</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"3D"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cube</span><span style="color: #0000FF;">,</span><span style="color: #000000;">test_node</span><span style="color: #0000FF;">,</span><span style="color: #004600;">true</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">N</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1_000_000</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">million</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">N</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">N</span> <span style="color: #008080;">do</span> <span style="color: #000000;">million</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rand_pt</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">test_node</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rand_pt</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Million"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">million</span><span style="color: #0000FF;">,</span><span style="color: #000000;">test_node</span><span style="color: #0000FF;">,</span><span style="color: #004600;">true</span><span style="color: #0000FF;">)</span>
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
<span style="color: #0000FF;">?</span><span style="color: #008000;">"done"</span>
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 2,183 ⟶ 4,148:
seen 43 nodes
average behaviour: visited 4267089 nodes for 100,000 random findings (42.670890 per lookup)
"35.8s"
</pre>
(Most of the time is taken up building the million tree.)
 
=={{header|Python}}==
{{trans|D}}
<langsyntaxhighlight lang="python">from random import seed, random
from time import clocktime
from operator import itemgetter
from collections import namedtuple
Line 2,311 ⟶ 4,278:
 
N = 400000
t0 = clocktime()
kd2 = KdTree(random_points(3, N), Orthotope(P(0, 0, 0), P(1, 1, 1)))
t1 = clocktime()
text = lambda *parts: "".join(map(str, parts))
show_nearest(2, text("k-d tree with ", N,
" random 3D points (generation time: ",
t1-t0, "s)"),
kd2, random_point(3))</langsyntaxhighlight>
{{out}}
<pre>Wikipedia example data:
Line 2,334 ⟶ 4,301:
=={{header|Racket}}==
The following code is optimized for readability.
<langsyntaxhighlight lang="racket">
#lang racket
 
Line 2,403 ⟶ 4,370:
n)]))
(nn 0 t (infinite-bb k)))
</syntaxhighlight>
</lang>
Tests:
<langsyntaxhighlight lang="racket">
(define (wikipedia-test)
(define t (kdtree 0 2 '(#(2 3) #(5 4) #(9 6) #(4 7) #(8 1) #(7 2))))
Line 2,433 ⟶ 4,400:
(test 3 1000)
(test 3 1000)
</syntaxhighlight>
</lang>
{{out}}
<langsyntaxhighlight lang="racket">
Wikipedia Test
Nearest neighbour to (9,2) is: #(8 1)
Line 2,456 ⟶ 4,423:
Control: 0.0018063471125121851
Visits: 39
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
(formerly Perl 6)
{{trans|Python}}
<syntaxhighlight lang="raku" perl6line>class Kd_node {
has $.d;
has $.split;
Line 2,586 ⟶ 4,553:
"k-d tree with $N random 3D points (generation time: {$t1 - $t0}s)",
$kd2, random_point(3));
}</langsyntaxhighlight>
{{out}}
<pre>Wikipedia example data:
Line 2,599 ⟶ 4,566:
Distance: 0.0340950700678338
Nodes visited: 23</pre>
 
=={{header|Rust}}==
<syntaxhighlight lang="rust">
use std::cmp::Ordering;
use std::cmp::Ordering::Less;
use std::ops::Sub;
use std::time::Instant;
 
use rand::prelude::*;
 
#[derive(Clone, PartialEq, Debug)]
struct Point {
pub coords: Vec<f32>,
}
 
impl<'a, 'b> Sub<&'b Point> for &'a Point {
type Output = Point;
 
fn sub(self, rhs: &Point) -> Point {
assert_eq!(self.coords.len(), rhs.coords.len());
Point {
coords: self
.coords
.iter()
.zip(rhs.coords.iter())
.map(|(&x, &y)| x - y)
.collect(),
}
}
}
 
impl Point {
fn norm_sq(&self) -> f32 {
self.coords.iter().map(|n| n * n).sum()
}
}
 
struct KDTreeNode {
point: Point,
dim: usize,
// Construction could become faster if we use an arena allocator,
// but this is easier to use.
left: Option<Box<KDTreeNode>>,
right: Option<Box<KDTreeNode>>,
}
 
impl KDTreeNode {
/// Create a new KDTreeNode around the `dim`th dimension.
/// Alternatively, we could dynamically determine the dimension to
/// split on by using the longest dimension.
pub fn new(points: &mut [Point], dim: usize) -> KDTreeNode {
let points_len = points.len();
if points_len == 1 {
return KDTreeNode {
point: points[0].clone(),
dim,
left: None,
right: None,
};
}
 
// Split around the median
let pivot = quickselect_by(points, points_len / 2, &|a, b| {
a.coords[dim].partial_cmp(&b.coords[dim]).unwrap()
});
 
let left = Some(Box::new(KDTreeNode::new(
&mut points[0..points_len / 2],
(dim + 1) % pivot.coords.len(),
)));
let right = if points.len() >= 3 {
Some(Box::new(KDTreeNode::new(
&mut points[points_len / 2 + 1..points_len],
(dim + 1) % pivot.coords.len(),
)))
} else {
None
};
 
KDTreeNode {
point: pivot,
dim,
left,
right,
}
}
 
pub fn find_nearest_neighbor<'a>(&'a self, point: &Point) -> (&'a Point, usize) {
self.find_nearest_neighbor_helper(point, &self.point, (point - &self.point).norm_sq(), 1)
}
 
fn find_nearest_neighbor_helper<'a>(
&'a self,
point: &Point,
best: &'a Point,
best_dist_sq: f32,
n_visited: usize,
) -> (&'a Point, usize) {
let mut my_best = best;
let mut my_best_dist_sq = best_dist_sq;
let mut my_n_visited = n_visited;
 
// We should always examine the near side
if self.point.coords[self.dim] < point.coords[self.dim] && self.right.is_some() {
let (a, b) = self.right.as_ref().unwrap().find_nearest_neighbor_helper(
point,
my_best,
my_best_dist_sq,
my_n_visited,
);
my_best = a;
my_n_visited = b;
} else if self.left.is_some() {
let (a, b) = self.left.as_ref().unwrap().find_nearest_neighbor_helper(
point,
my_best,
my_best_dist_sq,
my_n_visited,
);
my_best = a;
my_n_visited = b;
}
 
// distance along this node's axis
let axis_dist_sq = (self.point.coords[self.dim] - point.coords[self.dim]).powi(2);
if axis_dist_sq <= my_best_dist_sq {
// self can only be nearer than best if axis_dist_sq is less than
// best_dist_sq because axis_dist_sq is a lower bound for
// self_dist_sq
let self_dist_sq = (point - &self.point).norm_sq();
if self_dist_sq < my_best_dist_sq {
my_best = &self.point;
my_best_dist_sq = self_dist_sq;
}
 
// bookkeeping
my_n_visited += 1;
 
// same reasoning applies for the far side of the split
if self.point.coords[self.dim] < point.coords[self.dim] && self.left.is_some() {
let (a, b) = self.left.as_ref().unwrap().find_nearest_neighbor_helper(
point,
my_best,
my_best_dist_sq,
my_n_visited,
);
my_best = a;
my_n_visited = b;
} else if self.right.is_some() {
let (a, b) = self.right.as_ref().unwrap().find_nearest_neighbor_helper(
point,
my_best,
my_best_dist_sq,
my_n_visited,
);
my_best = a;
my_n_visited = b;
}
}
 
(my_best, my_n_visited)
}
}
 
pub fn main() {
let mut rng = thread_rng();
 
// wordpress
let mut wp_points: Vec<Point> = [
[2.0, 3.0],
[5.0, 4.0],
[9.0, 6.0],
[4.0, 7.0],
[8.0, 1.0],
[7.0, 2.0],
]
.iter()
.map(|x| Point { coords: x.to_vec() })
.collect();
let wp_tree = KDTreeNode::new(&mut wp_points, 0);
 
let wp_target = Point {
coords: vec![9.0, 2.0],
};
let (point, n_visited) = wp_tree.find_nearest_neighbor(&wp_target);
println!("Wikipedia example data:");
println!("Point: [9, 2]");
println!("Nearest neighbor: {:?}", point);
println!("Distance: {}", (point - &wp_target).norm_sq().sqrt());
println!("Nodes visited: {}", n_visited);
 
// randomly generated 3D
let n_random = 1000;
let mut make_random_point = || Point {
coords: (0..3).map(|_| (rng.gen::<f32>() - 0.5) * 1000.0).collect(),
};
let mut random_points: Vec<Point> = (0..n_random).map(|_| make_random_point()).collect();
 
let start_cons_time = Instant::now();
let random_tree = KDTreeNode::new(&mut random_points, 0);
let cons_time = start_cons_time.elapsed();
println!(
"1,000 3d points (Construction time: {}ms)",
cons_time.as_millis(),
);
 
let random_target = make_random_point();
 
let (point, n_visited) = random_tree.find_nearest_neighbor(&random_target);
println!("Point: {:?}", random_target);
println!("Nearest neighbor: {:?}", point);
println!("Distance: {}", (point - &random_target).norm_sq().sqrt());
println!("Nodes visited: {}", n_visited);
 
// benchmark search time
let n_searches = 1000;
let random_targets: Vec<Point> = (0..n_searches).map(|_| make_random_point()).collect();
 
let start_search_time = Instant::now();
let mut total_n_visited = 0;
for target in &random_targets {
let (_, n_visited) = random_tree.find_nearest_neighbor(target);
total_n_visited += n_visited;
}
let search_time = start_search_time.elapsed();
println!(
"Visited an average of {} nodes on {} searches in {} ms",
total_n_visited as f32 / n_searches as f32,
n_searches,
search_time.as_millis(),
);
}
 
fn quickselect_by<T>(arr: &mut [T], position: usize, cmp: &dyn Fn(&T, &T) -> Ordering) -> T
where
T: Clone,
{
// We use `thread_rng` here because it was already initialized in `main`.
let mut pivot_index = thread_rng().gen_range(0, arr.len());
// Need to wrap in another closure or we get ownership complaints.
// Tried using an unboxed closure to get around this but couldn't get it to work.
pivot_index = partition_by(arr, pivot_index, &|a: &T, b: &T| cmp(a, b));
let array_len = arr.len();
match position.cmp(&pivot_index) {
Ordering::Equal => arr[position].clone(),
Ordering::Less => quickselect_by(&mut arr[0..pivot_index], position, cmp),
Ordering::Greater => quickselect_by(
&mut arr[pivot_index + 1..array_len],
position - pivot_index - 1,
cmp,
),
}
}
 
fn partition_by<T>(arr: &mut [T], pivot_index: usize, cmp: &dyn Fn(&T, &T) -> Ordering) -> usize {
let array_len = arr.len();
arr.swap(pivot_index, array_len - 1);
let mut store_index = 0;
for i in 0..array_len - 1 {
if cmp(&arr[i], &arr[array_len - 1]) == Less {
arr.swap(i, store_index);
store_index += 1;
}
}
arr.swap(array_len - 1, store_index);
store_index
}
</syntaxhighlight>
{{out}}
<pre>
Wikipedia example data:
Point: [9, 2]
Nearest neighbor: Point { coords: [8.0, 1.0] }
Distance: 1.4142135
Nodes visited: 4
1,000 3d points (Construction time: 6ms)
Point: Point { coords: [-353.30945, 277.02594, -260.73093] }
Nearest neighbor: Point { coords: [-345.98798, -24.195671, -350.5432] }
Distance: 314.41107
Nodes visited: 183
Visited an average of 351.573 nodes on 1000 searches in 415 ms
</pre>
 
=={{header|Scala}}==
This example works for sequences of Int, Double, etc, so it is non-minimal due to its type-safe Numeric parameterisation.
<langsyntaxhighlight Scalalang="scala">object KDTree {
import Numeric._
 
Line 2,652 ⟶ 4,901:
def compare[T](a: Seq[T], b: Seq[T])(implicit num: Numeric[T]): Int =
a.zip(b).find(c => num.compare(c._1, c._2) != 0).map(c => num.compare(c._1, c._2)).getOrElse(0)
}</langsyntaxhighlight>
Task test:
<langsyntaxhighlight Scalalang="scala">object KDTreeTest extends App {
def test[T](haystack: Seq[Seq[T]], needles: Seq[T]*)(implicit num: Numeric[T]) = {
println
Line 2,688 ⟶ 4,937:
assume(small.size == 27)
test(small, List(0, 0, 0), List(4, 5, 6))
}</langsyntaxhighlight>
{{out}}
<pre>KDNode(List(7, 2),Some(KDNode(List(5, 4),Some(KDNode(List(2, 3),None,None,0)),Some(KDNode(List(4, 7),None,None,0)),1)),Some(KDNode(List(9, 6),Some(KDNode(List(8, 1),None,None,0)),None,1)),0)
Line 2,704 ⟶ 4,953:
=={{header|Sidef}}==
{{trans|Raku}}
<langsyntaxhighlight lang="ruby">struct Kd_node {
d,
split,
Line 2,829 ⟶ 5,078:
show_nearest(2,
"k-d tree with #{N} random 3D points (generation time: #{t1 - t0}s)",
kd2, random_point(3))</langsyntaxhighlight>
{{out}}
<pre>
Line 2,848 ⟶ 5,097:
{{trans|Python}}
{{libheader|TclOO}}
<langsyntaxhighlight lang="tcl">package require TclOO
 
oo::class create KDTree {
Line 2,916 ⟶ 5,165:
return [list $nearest $dist2 $nodesVisited]
}
}</langsyntaxhighlight>
Demonstration code:
<langsyntaxhighlight lang="tcl">proc showNearest {heading tree point} {
puts ${heading}:
puts "Point: \[[join $point ,]\]"
Line 2,954 ⟶ 5,203:
set t [time {KDTree create kd2 [randomPoints 3 $N]}]
showNearest "k-d tree with $N random 3D points (generation time: [lindex $t 0] us)" kd2 [randomPoint 3]
puts "Search time: [time {kd2 findNearest [randomPoint 3]} 10000]"</langsyntaxhighlight>
{{out}}
<pre>
Line 2,975 ⟶ 5,224:
Nodes visited: 22
Search time: 289.894755 microseconds per iteration
</pre>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-dynamic}}
{{libheader|Wren-math}}
{{libheader|Wren-seq}}
{{libheader|Wren-sort}}
<syntaxhighlight lang="wren">import "./dynamic" for Tuple
import "./math" for Nums
import "./seq" for Lst
import "./sort" for Sort
import "random" for Random
 
// A Point is represented by a 2 element List of Nums
var PtSqd = Fn.new { |p, q| Nums.sum(Lst.zip(p, q).map { |r| (r[0] - r[1]) * (r[0] - r[1]) }) }
 
var HyperRect = Tuple.create("HyperRect", ["min", "max"])
 
var HrCopy = Fn.new { |hr| HyperRect.new(hr.min.toList, hr.max.toList) }
 
var NearestNeighbor = Tuple.create("NearestNeighbor", ["nearest", "distSqd", "nodesVisited"])
 
var KdNode = Tuple.create("KdNode", ["domElt", "split", "left", "right"])
 
class KdTree {
construct new(pts, bounds) {
var nk2 // recursive closure
nk2 = Fn.new { |exset, split|
if (exset.count == 0) return null
var cmp = Fn.new { |p, q| (p[split] - q[split]).sign }
Sort.quick(exset, 0, exset.count - 1, cmp)
var m = (exset.count/2).floor
var d = exset[m]
while (m + 1 < exset.count && exset[m + 1][split] == d[split]) m = m + 1
var s2 = split + 1
if (s2 == d.count) s2 = 0
return KdNode.new(
d,
split,
nk2.call(exset[0...m], s2),
nk2.call(exset[m + 1..-1], s2)
)
}
_n = nk2.call(pts, 0)
_bounds = bounds
}
 
nearest(p) { nn_(_n, p, _bounds, 1/0) }
 
nn_(kd, target, hr, maxDistSqd) {
if (!kd) return NearestNeighbor.new(null, 1/0, 0)
var nodesVisited = 1
var s = kd.split
var pivot = kd.domElt
var leftHr = HrCopy.call(hr)
var rightHr = HrCopy.call(hr)
leftHr.max[s] = pivot[s]
rightHr.min[s] = pivot[s]
var targetInLeft = target[s] <= pivot[s]
var nearerKd = (targetInLeft) ? kd.left : kd.right
var nearerHr = (targetInLeft) ? leftHr : rightHr
var furtherKd = (targetInLeft) ? kd.right : kd.left
var furtherHr = (targetInLeft) ? rightHr : leftHr
var res = nn_(nearerKd, target, nearerHr, maxDistSqd)
var nearest = res.nearest
var distSqd = res.distSqd
var nv = res.nodesVisited
nodesVisited = nodesVisited + nv
var maxDistSqd2 = (distSqd < maxDistSqd) ? distSqd : maxDistSqd
var d = pivot[s] - target[s]
d = d * d
if (d > maxDistSqd2) return NearestNeighbor.new(nearest, distSqd, nodesVisited)
d = PtSqd.call(pivot, target)
if (d < distSqd) {
nearest = pivot
distSqd = d
maxDistSqd2 = distSqd
}
var temp = nn_(furtherKd, target, furtherHr, maxDistSqd2)
nodesVisited = nodesVisited + temp.nodesVisited
if (temp.distSqd < distSqd) {
nearest = temp.nearest
distSqd = temp.distSqd
}
return NearestNeighbor.new(nearest, distSqd, nodesVisited)
}
}
 
var rand = Random.new()
 
var randomPt = Fn.new { |dim|
var pt = List.filled(dim, 0)
for (i in 0...dim) pt[i] = rand.float()
return pt
}
 
var randomPts = Fn.new { |dim, n|
var pts = List.filled(n, null)
for (i in 0...n) pts[i] = randomPt.call(dim)
return pts
}
 
var showNearest = Fn.new { |heading, kd, p|
System.print("%(heading):")
System.print("Point : %(p)")
var res = kd.nearest(p)
System.print("Nearest neighbor : %(res.nearest)")
System.print("Distance : %(res.distSqd.sqrt)")
System.print("Nodes visited : %(res.nodesVisited)")
System.print()
}
 
var points = [[2, 3], [5, 4], [9, 6], [4, 7], [8, 1], [7, 2]]
var hr = HyperRect.new([0, 0], [10, 10])
var kd = KdTree.new(points, hr)
showNearest.call("WP example data", kd, [9, 2])
 
hr = HyperRect.new([0, 0, 0], [1, 1, 1])
kd = KdTree.new(randomPts.call(3, 1000), hr)
showNearest.call("1,000 random 3D points", kd, randomPt.call(3))
 
hr = HrCopy.call(hr)
kd = KdTree.new(randomPts.call(3, 400000), hr)
showNearest.call("400,000 random 3D points", kd, randomPt.call(3))</syntaxhighlight>
 
{{out}}
Sample output:
<pre>
WP example data:
Point : [9, 2]
Nearest neighbor : [8, 1]
Distance : 1.4142135623731
Nodes visited : 3
 
1000 random 3D points:
Point : [0.12939208666935, 0.59363898087134, 0.055267216633677]
Nearest neighbor : [0.11864823194614, 0.56792856962105, 0.064465652254435]
Distance : 0.029343941092531
Nodes visited : 17
 
400,000 random 3D points:
Point : [0.90399249951976, 0.76753089149634, 0.81889978227179]
Nearest neighbor : [0.90977751130258, 0.77238453898072, 0.82103471724632]
Distance : 0.007847432865301
Nodes visited : 30
</pre>
 
=={{header|zkl}}==
{{trans|Python}}
<langsyntaxhighlight lang="zkl">class KdTree{
const NEAREST=0, DIST_SQD=1, NODES_VISITED=2;
class KdNode{
Line 3,041 ⟶ 5,436:
println("Nodes visited: ", n[NODES_VISITED], "\n");
}
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">class Orthotope{ fcn init(mi,ma){ var min=mi,max=ma; } }
kd1:=KdTree(T(T(2,3), T(5,4), T(9,6), T(4,7), T(8,1), T(7,2)),
Orthotope(List(0,0), List(10,10)));
kd1.show_nearest(2, "Wikipedia example data", T(9,2));</langsyntaxhighlight>
{{out}}
<pre>
Line 3,055 ⟶ 5,450:
Nodes visited: 3
</pre>
<langsyntaxhighlight lang="zkl">fcn randomPoint(k){ k.pump(List,(0.0).random(1)) } // ( (p1,p2,,pk), ... n of them), p in [0..1]
fcn randomPoints(k,n){ // ( (p1,p2,,pk), ... n of them), p in [0..1]
n.pump(List,randomPoint.fp(k))
Line 3,063 ⟶ 5,458:
kd2:=KdTree(randomPoints(3,N), Orthotope(L(0,0,0), L(1,1,1)));
kd2.show_nearest(2, String("k-d tree with ", N," random 3D points"),
randomPoint(3));</langsyntaxhighlight>
{{out}}
<pre>
2,442

edits