Skip to content

Commit

Permalink
Removed the legacy KD tree code from building.
Browse files Browse the repository at this point in the history
  • Loading branch information
PoneyClairDeLune committed Jan 25, 2025
1 parent 3882f62 commit 53bc815
Show file tree
Hide file tree
Showing 2 changed files with 1 addition and 309 deletions.
2 changes: 1 addition & 1 deletion dist/kd-tree.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"use strict";let a=class{left=null;right=null;obj;parent;dimension;constructor(t,e,i){let l=this;l.obj=t,l.parent=i,l.dimension=e}};function o(u){this.content=[],this.scoreFunction=u}o.prototype={push:function(u){this.content.push(u),this.bubbleUp(this.content.length-1)},pop:function(){let u=this.content[0],t=this.content.pop();return this.content.length>0&&(this.content[0]=t,this.sinkDown(0)),u},peek:function(){return this.content[0]},remove:function(u){for(let t=this.content.length,e=0;e<t;e++)if(this.content[e]==u){let i=this.content.pop();e!=t-1&&(this.content[e]=i,this.scoreFunction(i)<this.scoreFunction(u)?this.bubbleUp(e):this.sinkDown(e));return}throw new Error("Node not found.")},size:function(){return this.content.length},bubbleUp:function(u){for(let t=this.content[u];u>0;){let e=Math.floor((u+1)/2)-1,i=this.content[e];if(this.scoreFunction(t)<this.scoreFunction(i))this.content[e]=t,this.content[u]=i,u=e;else break}},sinkDown:function(u){for(let t=this.content.length,e=this.content[u],i=this.scoreFunction(e);;){let l=(u+1)*2,r=l-1,n=null;if(r<t){let f=this.content[r],h=this.scoreFunction(f);h<i&&(n=r)}if(l<t){let g=this.content[l],c=this.scoreFunction(g);c<(n==null?i:h)&&(n=l)}if(n!=null)this.content[u]=this.content[n],this.content[n]=e,u=n;else break}}};let j=class{#t;#i;root;get dimensions(){return this.#t}get metric(){return this.#i}#l(t,e,i){let l=this,r=e%l.#t.length;if(t.length===0)return null;if(t.length===1)return new a(t[0],r,i);t.sort((h,g)=>h[l.#t[r]]-g[l.#t[r]]);let n=t.length>>1,f=new a(t[n],r,i);return f.left=l.#l(t.slice(0,n),e+1,f),f.right=l.#l(t.slice(n+1),e+1,f),f}#r(t){let e=this;t.left&&(t.left.parent=t,e.#r(t.left)),t.right&&(t.right.parent=t,e.#r(t.right))}#a(t){this.root=t,this.#r(this.root)}#n(t,e,i){if(t===null)return e;let l=dimensions[t.dimension];return i[l]<t.obj[l]?upThis.#n(t.left,t,i):upThis.#n(t.right,t,i)}#u(t,e){let i=this;if(t===null)return null;if(t.obj===e)return t;let l=i.#t[t.dimension];return e[l]<t.obj[l]?i.#u(t.left,e):i.#u(t.right,e)}#e(t,e){let i=this;if(t===null)return null;let l=i.#t[e];if(t.dimension===e)return t.left!=null?i.#e(t.left,e):t;let r=t.obj[l],n=i.#e(t.left,e),f=i.#e(t.right,e),h=t;return n!=null&&n.obj[l]<r&&(h=n),f!=null&&f.obj[l]<h.obj[l]&&(h=f),h}#f(t){let e=this;if(t.left===null&&t.right===null){if(t.parent===null){e.root=null;return}let i=e.#t[t.parent.dimension];t.obj[i]<t.parent.obj[i]?t.parent.left=null:t.parent.right=null;return}if(t.right==null){let i=e.#e(t.left,t.dimension),l=i.obj;e.#f(i),t.right=t.left,t.left=null,t.obj=l}else{let i=e.#e(t.right,t.dimension),l=i.obj;e.#f(i),t.obj=l}}#g(t,e,i,l){i.push([t,e]),i.size()>l&&i.pop()}#h(t,e,i,l){let r=this,n=r.#t[t.dimension],f=r.#i(e,t.obj),h=[];for(let s=0;s<r.#t.length;s++)s===t.dimension?h[r.#t[s]]=e[r.#t[s]]:h[r.#t[s]]=t.obj[r.#t[s]];let g=r.#i(h,t.obj);if(t.right===null&&t.left===null){(i.size()<l||f<i.peek()[1])&&r.#g(t,f,i,l);return}let c;if(t.right===null?c=t.left:t.left===null?c=t.right:e[n]<t.obj[n]?c=t.left:c=t.right,r.#h(c,e,i,l),(i.size()<l||f<i.peek()[1])&&r.#g(t,f,i,l),i.size()<l||Math.abs(g)<i.peek()[1]){let s;c===t.left?s=t.right:s=t.left,s!=null&&r.#h(s,e,i,l)}}#s(t){return t==null?0:Math.max(this.#s(t.left),this.#s(t.right))+1}#c(t){return t==null?0:this.#c(t.left)+this.#c(t.right)+1}toJSON(t){let e=this;t||(t=e.root);let i=new a(t.obj,t.dimension,null);return t.left&&(i.left=e.toJSON(t.left)),t.right&&(i.right=e.toJSON(t.right)),i}insert(t){let e=this,i=e.#n(e.root,null,t);if(i===null){e.root=new a(t,0,null);return}let l=new a(t,(i.dimension+1)%e.#t.length,i),r=e.#t[i.dimension];t[r]<i.obj[r]?i.left=l:i.right=l}remove(t){let e=this,i=e.#u(e.root,t);i!==null&&e.#f(i)}nearest(t,e,i){let l=new o(n=>-n[1]);if(i)for(let n=0;n<e;n++)l.push([null,i]);this.root&&this.#h(this.root,t,l,e);let r=[];for(let n=0;n<Math.min(e,l.content.length);n++)l.content[n][0]&&r.push([l.content[n][0].obj,l.content[n][1]]);return r}balanceFactor(){let t=this;return t.#s(t.root)/Math.log(t.#c(t.root))/Math.LN2}constructor(t,e,i){let l=this;l.#t=i,l.#i=e,Array.isArray(t)?l.root=l.#l(t,0,null):l.#a(t,e,i)}};export{j as KDTree,o as KDTreeBinaryHeap};
"use strict";let g=class{left=null;right=null;obj;parent;dimension;constructor(t,e,i){let l=this;l.obj=t,l.parent=i,l.dimension=e}};function a(h){this.content=[],this.scoreFunction=h}a.prototype={push:function(h){this.content.push(h),this.bubbleUp(this.content.length-1)},pop:function(){let h=this.content[0],t=this.content.pop();return this.content.length>0&&(this.content[0]=t,this.sinkDown(0)),h},peek:function(){return this.content[0]},remove:function(h){for(let t=this.content.length,e=0;e<t;e++)if(this.content[e]==h){let i=this.content.pop();e!=t-1&&(this.content[e]=i,this.scoreFunction(i)<this.scoreFunction(h)?this.bubbleUp(e):this.sinkDown(e));return}throw new Error("Node not found.")},size:function(){return this.content.length},bubbleUp:function(h){for(let t=this.content[h];h>0;){let e=Math.floor((h+1)/2)-1,i=this.content[e];if(this.scoreFunction(t)<this.scoreFunction(i))this.content[e]=t,this.content[h]=i,h=e;else break}},sinkDown:function(h){for(let t=this.content.length,e=this.content[h],i=this.scoreFunction(e);;){let l=(h+1)*2,n=l-1,r=null;if(n<t){let u=this.content[n],s=this.scoreFunction(u);s<i&&(r=n)}if(l<t){let c=this.content[l],o=this.scoreFunction(c);o<(r==null?i:s)&&(r=l)}if(r!=null)this.content[h]=this.content[r],this.content[r]=e,h=r;else break}}};let j=class{#t;#i;root;get dimensions(){return this.#t}get metric(){return this.#i}#l(t,e,i){let l=this,n=e%l.#t.length;if(t.length===0)return null;if(t.length===1)return new g(t[0],n,i);t.sort((s,c)=>s[l.#t[n]]-c[l.#t[n]]);let r=t.length>>1,u=new g(t[r],n,i);return u.left=l.#l(t.slice(0,r),e+1,u),u.right=l.#l(t.slice(r+1),e+1,u),u}#n(t){let e=this;t.left&&(t.left.parent=t,e.#n(t.left)),t.right&&(t.right.parent=t,e.#n(t.right))}#g(t){this.root=t,this.#n(this.root)}#r(t,e,i){if(t===null)return e;let l=dimensions[t.dimension];return i[l]<t.obj[l]?upThis.#r(t.left,t,i):upThis.#r(t.right,t,i)}#h(t,e){let i=this;if(t===null)return null;if(t.obj===e)return t;let l=i.#t[t.dimension];return e[l]<t.obj[l]?i.#h(t.left,e):i.#h(t.right,e)}#e(t,e){let i=this;if(t===null)return null;let l=i.#t[e];if(t.dimension===e)return t.left!=null?i.#e(t.left,e):t;let n=t.obj[l],r=i.#e(t.left,e),u=i.#e(t.right,e),s=t;return r!=null&&r.obj[l]<n&&(s=r),u!=null&&u.obj[l]<s.obj[l]&&(s=u),s}#u(t){let e=this;if(t.left===null&&t.right===null){if(t.parent===null){e.root=null;return}let i=e.#t[t.parent.dimension];t.obj[i]<t.parent.obj[i]?t.parent.left=null:t.parent.right=null;return}if(t.right==null){let i=e.#e(t.left,t.dimension),l=i.obj;e.#u(i),t.right=t.left,t.left=null,t.obj=l}else{let i=e.#e(t.right,t.dimension),l=i.obj;e.#u(i),t.obj=l}}#c(t,e,i,l){i.push([t,e]),i.size()>l&&i.pop()}#s(t,e,i,l){let n=this,r=n.#t[t.dimension],u=n.#i(e,t.obj),s=[];for(let f=0;f<n.#t.length;f++)f===t.dimension?s[n.#t[f]]=e[n.#t[f]]:s[n.#t[f]]=t.obj[n.#t[f]];let c=n.#i(s,t.obj);if(t.right===null&&t.left===null){(i.size()<l||u<i.peek()[1])&&n.#c(t,u,i,l);return}let o;if(t.right===null?o=t.left:t.left===null?o=t.right:e[r]<t.obj[r]?o=t.left:o=t.right,n.#s(o,e,i,l),(i.size()<l||u<i.peek()[1])&&n.#c(t,u,i,l),i.size()<l||Math.abs(c)<i.peek()[1]){let f;o===t.left?f=t.right:f=t.left,f!=null&&n.#s(f,e,i,l)}}#f(t){return t==null?0:Math.max(this.#f(t.left),this.#f(t.right))+1}#o(t){return t==null?0:this.#o(t.left)+this.#o(t.right)+1}toJSON(t){let e=this;t||(t=e.root);let i=new g(t.obj,t.dimension,null);return t.left&&(i.left=e.toJSON(t.left)),t.right&&(i.right=e.toJSON(t.right)),i}insert(t){let e=this,i=e.#r(e.root,null,t);if(i===null){e.root=new g(t,0,null);return}let l=new g(t,(i.dimension+1)%e.#t.length,i),n=e.#t[i.dimension];t[n]<i.obj[n]?i.left=l:i.right=l}remove(t){let e=this,i=e.#h(e.root,t);i!==null&&e.#u(i)}nearest(t,e,i){let l=new a(r=>-r[1]);if(i)for(let r=0;r<e;r++)l.push([null,i]);this.root&&this.#s(this.root,t,l,e);let n=[];for(let r=0;r<Math.min(e,l.content.length);r++)l.content[r][0]&&n.push([l.content[r][0].obj,l.content[r][1]]);return n}balanceFactor(){let t=this;return t.#f(t.root)/Math.log(t.#o(t.root))/Math.LN2}constructor(t,e,i){let l=this;l.#t=i,l.#i=e,Array.isArray(t)?l.root=l.#l(t,0,null):l.#g(t,e,i)}};export{j as KDTree,a as KDTreeBinaryHeap};
/**
* k-d Tree JavaScript - v1.1
*
Expand Down
308 changes: 0 additions & 308 deletions src/kd-tree/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -427,314 +427,6 @@ let KDTree = class KDTree {
};
};

function kdTree(points, metric, dimensions) {

var self = this;

function buildTree(points, depth, parent) {
var dim = depth % dimensions.length,
median,
node;

if (points.length === 0) {
return null;
}
if (points.length === 1) {
return new Node(points[0], dim, parent);
}

points.sort(function (a, b) {
return a[dimensions[dim]] - b[dimensions[dim]];
});

median = Math.floor(points.length / 2);
node = new Node(points[median], dim, parent);
node.left = buildTree(points.slice(0, median), depth + 1, node);
node.right = buildTree(points.slice(median + 1), depth + 1, node);

return node;
}

// Reloads a serialied tree
function loadTree (data) {
// Just need to restore the `parent` parameter
self.root = data;

function restoreParent (root) {
if (root.left) {
root.left.parent = root;
restoreParent(root.left);
}

if (root.right) {
root.right.parent = root;
restoreParent(root.right);
}
}

restoreParent(self.root);
}

// If points is not an array, assume we're loading a pre-built tree
if (!Array.isArray(points)) loadTree(points, metric, dimensions);
else this.root = buildTree(points, 0, null);

// Convert to a JSON serializable structure; this just requires removing
// the `parent` property
this.toJSON = function (src) {
if (!src) src = this.root;
var dest = new Node(src.obj, src.dimension, null);
if (src.left) dest.left = self.toJSON(src.left);
if (src.right) dest.right = self.toJSON(src.right);
return dest;
};

this.insert = function (point) {
function innerSearch(node, parent) {

if (node === null) {
return parent;
}

var dimension = dimensions[node.dimension];
if (point[dimension] < node.obj[dimension]) {
return innerSearch(node.left, node);
} else {
return innerSearch(node.right, node);
}
}

var insertPosition = innerSearch(this.root, null),
newNode,
dimension;

if (insertPosition === null) {
this.root = new Node(point, 0, null);
return;
}

newNode = new Node(point, (insertPosition.dimension + 1) % dimensions.length, insertPosition);
dimension = dimensions[insertPosition.dimension];

if (point[dimension] < insertPosition.obj[dimension]) {
insertPosition.left = newNode;
} else {
insertPosition.right = newNode;
}
};

this.remove = function (point) {
var node;

function nodeSearch(node) {
if (node === null) {
return null;
}

if (node.obj === point) {
return node;
}

var dimension = dimensions[node.dimension];

if (point[dimension] < node.obj[dimension]) {
return nodeSearch(node.left, node);
} else {
return nodeSearch(node.right, node);
}
}

function removeNode(node) {
var nextNode,
nextObj,
pDimension;

function findMin(node, dim) {
var dimension,
own,
left,
right,
min;

if (node === null) {
return null;
}

dimension = dimensions[dim];

if (node.dimension === dim) {
if (node.left !== null) {
return findMin(node.left, dim);
}
return node;
}

own = node.obj[dimension];
left = findMin(node.left, dim);
right = findMin(node.right, dim);
min = node;

if (left !== null && left.obj[dimension] < own) {
min = left;
}
if (right !== null && right.obj[dimension] < min.obj[dimension]) {
min = right;
}
return min;
}

if (node.left === null && node.right === null) {
if (node.parent === null) {
self.root = null;
return;
}

pDimension = dimensions[node.parent.dimension];

if (node.obj[pDimension] < node.parent.obj[pDimension]) {
node.parent.left = null;
} else {
node.parent.right = null;
}
return;
}

// If the right subtree is not empty, swap with the minimum element on the
// node's dimension. If it is empty, we swap the left and right subtrees and
// do the same.
if (node.right !== null) {
nextNode = findMin(node.right, node.dimension);
nextObj = nextNode.obj;
removeNode(nextNode);
node.obj = nextObj;
} else {
nextNode = findMin(node.left, node.dimension);
nextObj = nextNode.obj;
removeNode(nextNode);
node.right = node.left;
node.left = null;
node.obj = nextObj;
}

}

node = nodeSearch(self.root);

if (node === null) { return; }

removeNode(node);
};

this.nearest = function (point, maxNodes, maxDistance) {
var i,
result,
bestNodes;

bestNodes = new BinaryHeap(
function (e) { return -e[1]; }
);

function nearestSearch(node) {
var bestChild,
dimension = dimensions[node.dimension],
ownDistance = metric(point, node.obj),
linearPoint = {},
linearDistance,
otherChild,
i;

function saveNode(node, distance) {
bestNodes.push([node, distance]);
if (bestNodes.size() > maxNodes) {
bestNodes.pop();
}
}

for (i = 0; i < dimensions.length; i += 1) {
if (i === node.dimension) {
linearPoint[dimensions[i]] = point[dimensions[i]];
} else {
linearPoint[dimensions[i]] = node.obj[dimensions[i]];
}
}

linearDistance = metric(linearPoint, node.obj);

if (node.right === null && node.left === null) {
if (bestNodes.size() < maxNodes || ownDistance < bestNodes.peek()[1]) {
saveNode(node, ownDistance);
}
return;
}

if (node.right === null) {
bestChild = node.left;
} else if (node.left === null) {
bestChild = node.right;
} else {
if (point[dimension] < node.obj[dimension]) {
bestChild = node.left;
} else {
bestChild = node.right;
}
}

nearestSearch(bestChild);

if (bestNodes.size() < maxNodes || ownDistance < bestNodes.peek()[1]) {
saveNode(node, ownDistance);
}

if (bestNodes.size() < maxNodes || Math.abs(linearDistance) < bestNodes.peek()[1]) {
if (bestChild === node.left) {
otherChild = node.right;
} else {
otherChild = node.left;
}
if (otherChild !== null) {
nearestSearch(otherChild);
}
}
}

if (maxDistance) {
for (i = 0; i < maxNodes; i += 1) {
bestNodes.push([null, maxDistance]);
}
}

if(self.root)
nearestSearch(self.root);

result = [];

for (i = 0; i < Math.min(maxNodes, bestNodes.content.length); i += 1) {
if (bestNodes.content[i][0]) {
result.push([bestNodes.content[i][0].obj, bestNodes.content[i][1]]);
}
}
return result;
};

this.balanceFactor = function () {
function height(node) {
if (node === null) {
return 0;
}
return Math.max(height(node.left), height(node.right)) + 1;
}

function count(node) {
if (node === null) {
return 0;
}
return count(node.left) + count(node.right) + 1;
}

return height(self.root) / (Math.log(count(self.root)) / Math.log(2));
};
}

export {
KDTree,
BinaryHeap as KDTreeBinaryHeap
Expand Down

0 comments on commit 53bc815

Please sign in to comment.