forked from fpirsch/vptree.js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
vptree.min.js
3 lines (3 loc) · 4.94 KB
/
vptree.min.js
1
2
3
/* vptree.js v0.1.1 | https://github.com/fpirsch/vptree.js | ISC Licence. François Pirsch. 2013.
*/
"use strict";(function(root,factory){if(typeof define==="function"&&define.amd){define(["exports"],function(exports){factory(root.VPTreeFactory=exports)})}else if(typeof exports==="object"){factory(exports)}else{factory(root.VPTreeFactory={})}})(this,function(exports){function partition(list,left,right,pivotIndex,comp){var pivotValue=list[pivotIndex];var swap=list[pivotIndex];list[pivotIndex]=list[right];list[right]=swap;var storeIndex=left;for(var i=left;i<right;i++){if(comp(list[i],pivotValue)){swap=list[storeIndex];list[storeIndex]=list[i];list[i]=swap;storeIndex++}}swap=list[right];list[right]=list[storeIndex];list[storeIndex]=swap;return storeIndex}function medianOf3(list,a,b,c,comp){var A=list[a],B=list[b],C=list[c];return comp(A,B)?comp(B,C)?b:comp(A,C)?c:a:comp(A,C)?a:comp(B,C)?c:b}function nth_element(list,left,nth,right,comp){if(nth<=0||nth>right-left+1)throw"VPTree.nth_element: nth must be in range [1, right-left+1] (nth="+nth+")";var pivotIndex,pivotNewIndex,pivotDist;for(;;){pivotIndex=medianOf3(list,left,right,left+right>>1,comp);pivotNewIndex=partition(list,left,right,pivotIndex,comp);pivotDist=pivotNewIndex-left+1;if(pivotDist===nth){return list[pivotNewIndex]}else if(nth<pivotDist){right=pivotNewIndex-1}else{nth-=pivotDist;left=pivotNewIndex+1}}}function select(list,k,comp){if(k<0||k>=list.length)throw"VPTree.select: k must be in range [0, list.length-1] (k="+k+")";return nth_element(list,0,k+1,list.length-1,comp)}function selectVPIndex(list){return Math.floor(Math.random()*list.length)}var distanceComparator=function(a,b){return a.dist<b.dist};function buildVPTree(S,distance,nb){var list=[];for(var i=0,n=S.length;i<n;i++){list[i]={i:i}}var tree=recurseVPTree(S,list,distance,nb);return new VPTree(S,distance,tree)}function recurseVPTree(S,list,distance,nb){if(list.length===0)return null;var listLength=list.length;if(nb>0&&listLength<=nb){var bucket=[];for(var i=0;i<listLength;i++){bucket[i]=list[i].i}return bucket}var vpIndex=selectVPIndex(list),node=list[vpIndex];list.splice(vpIndex,1);listLength--;delete node.dist;if(listLength===0)return node;var vp=S[node.i],dmin=Infinity,dmax=0,item,dist;for(var i=0,n=listLength;i<n;i++){item=list[i];dist=distance(vp,S[item.i]);item.dist=dist;if(dmin>dist)dmin=dist;if(dmax<dist)dmax=dist}node.m=dmin;node.M=dmax;var medianIndex=listLength>>1,median=select(list,medianIndex,distanceComparator);var leftItems=list.splice(0,medianIndex),rightItems=list;node.μ=median.dist;node.L=recurseVPTree(S,leftItems,distance,nb);node.R=recurseVPTree(S,rightItems,distance,nb);return node}function stringify(root){var stack=[root||this.tree],s="";while(stack.length){var node=stack.pop();if(node.length)return"["+node.join(",")+"]";s+="{i:"+node.i;if(node.hasOwnProperty("m")){s+=",m:"+node.m+",M:"+node.M+",μ:"+node.μ}if(node.hasOwnProperty("b")){s+=",b:["+node.b+"]"}if(node.hasOwnProperty("L")){var L=node.L;if(L){s+=",L:";if(L.length)s+="["+L+"]";else s+=stringify(L)}}if(node.hasOwnProperty("R")){var R=node.R;if(R){s+=",R:";if(R.length)s+="["+R+"]";else s+=stringify(R)}}s+="}"}return s}exports.select=select;exports.build=buildVPTree;function PriorityQueue(size){size=size||5;var contents=[];function binaryIndexOf(priority){var minIndex=0,maxIndex=contents.length-1,currentIndex,currentElement;while(minIndex<=maxIndex){currentIndex=minIndex+maxIndex>>1;currentElement=contents[currentIndex].priority;if(currentElement<priority){minIndex=currentIndex+1}else if(currentElement>priority){maxIndex=currentIndex-1}else{return currentIndex}}return-1-minIndex}var api={get length(){return contents.length},insert:function(data,priority){var index=binaryIndexOf(priority);if(index<0)index=-1-index;if(index<size){contents.splice(index,0,{data:data,priority:priority});if(contents.length>size){contents.length--}}return contents.length===size?contents[contents.length-1].priority:Infinity},list:function(){return contents.map(function(item){return{i:item.data,d:item.priority}})}};return api}function searchVPTree(q,n){n=n||1;var W=new PriorityQueue(n),τ=Infinity,S=this.S,distance=this.distance,comparisons=0;function doSearch(node){if(node===null)return;if(node.length){for(var i=0,n=node.length;i<n;i++){comparisons++;var elementID=node[i],element=S[elementID],elementDist=distance(q,element);if(elementDist<τ){τ=W.insert(elementID,elementDist)}}return}var id=node.i,p=S[id],dist=distance(q,p);comparisons++;if(dist<τ){τ=W.insert(id,dist)}var μ=node.μ,L=node.L,R=node.R;if(μ===undefined)return;if(dist<μ){if(L&&node.m-τ<dist)doSearch(L);if(R&&μ-τ<dist&&dist<node.M+τ)doSearch(R)}else{if(R&&dist<node.M+τ)doSearch(R);if(L&&node.m-τ<dist&&dist<μ+τ)doSearch(L)}}doSearch(this.tree);this.comparisons=comparisons;return W.list()}function VPTree(S,distance,tree){this.S=S;this.distance=distance;this.tree=tree;this.search=searchVPTree;this.comparisons=0;this.stringify=stringify}exports.load=function(S,distance,tree){return new VPTree(S,distance,tree)}});