diff --git a/dist/druid.js b/dist/druid.js index 149b6bf..e4ec7c5 100755 --- a/dist/druid.js +++ b/dist/druid.js @@ -1,4 +1,4 @@ -// https://renecutura.eu v0.1.8 Copyright 2020 Rene Cutura +// https://renecutura.eu v0.2.0 Copyright 2020 Rene Cutura (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : @@ -3928,6 +3928,7 @@ class OPTICS { this._expand_cluster(seeds, clusters[cluster_index]); } } + return this; } /** @@ -4136,7 +4137,7 @@ class LSP extends DR { } } -var version = "0.1.8"; +var version = "0.2.0"; exports.BallTree = BallTree; exports.FASTMAP = FASTMAP; diff --git a/dist/druid.min.js b/dist/druid.min.js index 0634bf2..fb69df4 100644 --- a/dist/druid.min.js +++ b/dist/druid.min.js @@ -1,2 +1,2 @@ -// https://renecutura.eu v0.1.8 Copyright 2020 Rene Cutura -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).druid=t.druid||{})}(this,(function(t){"use strict";function e(t,e){return Math.sqrt(s(t,e))}function r(t){let e=t.length,r=0,s=0;for(let i=0;i=Math.abs(e)?s+=r-n+e:s+=e-n+r,r=n}return r+s}function s(t,e){if(t.length!=e.length)return;let s=t.length,i=new Array(s);for(let r=0;r({i:t,j:r,distance:a[t][r]})).sort((t,e)=>t.distance-e.distance).slice(1,r+1);return a}function n(t,r=e){if(void 0===r)return;let s=t.length,i=new Array(s);for(let t=0;t=0;--i)s[i]=(i*e+(r-i)*t)/r;return s}function a(t,r=e){let s=null;if(t instanceof h){let[e,r]=t.shape;if(1===e)s=t.row(0);else{if(1!==r)throw"matrix must be 1d!";s=t.col(0)}}else s=t;let i=s.length,n=new Array(i);return n.fill(0),r(s,n)}class h{constructor(t=null,e=null,r=null){if(this._rows=t,this._cols=e,this._data=null,t&&e){if(!r)return this._data=new Float64Array(t*e),this;if("function"==typeof r){this._data=new Float64Array(t*e);for(let s=0;s(e===r?1:0)-1/t;for(let s=0;st[r]);if("col"===e)return new h(r,1,e=>t[e]);if("diag"===e)return new h(r,r,(e,r)=>e==r?t[e]:0);throw"1d array has NaN entries"}if(Array.isArray(t[0])||t[0]instanceof Float64Array){let e=t[0].length;for(let s=0;st[e][r])}}}row(t){let e=new Array(this._cols);for(let r=0;rthis.entry(e,t))}get T(){return this.transpose()}inverse(){const t=this._rows,e=this._cols;let r=new h(t,2*e,(t,r)=>r>=e?t===r-e?1:0:this.entry(t,r)),s=0,i=0;for(;s=0;--s){let t=r.entry(s,s);for(let i=0;ir.entry(t,s+e))}dot(t){if(t instanceof h){let e=this;if(e.shape[1]!==t.shape[0])throw`A.dot(B): A is a ${e.shape.join(" x ")}-Matrix, B is a ${t.shape.join(" x ")}-Matrix: \n A has ${e.shape[1]} cols and B ${t.shape[0]} rows. \n Must be equal!`;let s=e.shape[1];return new h(e.shape[0],t.shape[1],(i,n)=>{let o=e.row(i),a=t.col(n);for(let t=0;te*t[i]));return s}throw"B must be Matrix or Array"}outer(t){let e=this,r=e._data.length;if(r!=t._data.length)return;let s=new h;return s.shape=[r,r,(r,i)=>r<=i?e._data[r]*t._data[i]:s.entry(i,r)],s}concat(t,e="horizontal"){const r=this,[s,i]=r.shape,[n,o]=t.shape;if("horizontal"==e){if(s!=n)throw`A.concat(B, "horizontal"): A and B need same number of rows, A has ${s} rows, B has ${n} rows.`;const e=new h(s,i+o,"zeros");return e.set_block(0,0,r),e.set_block(0,i,t),e}if("vertical"==e){if(i!=o)throw`A.concat(B, "vertical"): A and B need same number of columns, A has ${i} columns, B has ${o} columns.`;const e=new h(s+n,i,"zeros");return e.set_block(0,0,r),e.set_block(s,0,t),e}if("diag"==e){const e=new h(s+n,i+o,"zeros");return e.set_block(0,0,r),e.set_block(s,i,t),e}throw`type must be "horizontal" or "vertical", but type is ${e}!`}set_block(t,e,r){let[s,i]=r.shape;for(let n=0;nthis._rows))for(let s=0;sthis._cols||this.set_entry(n+t,s+e,r.entry(n,s));return this}get_block(t,e,r=null,s=null){const[i,n]=this.shape;if(s=s||n,(r=r||i)<=t||s<=e)throw`\n end_row must be greater than start_row, and \n end_col must be greater than start_col, but\n end_row = ${r}, start_row = ${t}, end_col = ${s}, and start_col = ${e}!`;const o=new h(r-t,s-e,"zeros");for(let i=t,n=0;it[r])}_apply_colwise_array(t,e){const r=this._data,[s,i]=this.shape;for(let n=0;nt*e)}divide(t){return this.clone()._apply(t,(t,e)=>t/e)}add(t){return this.clone()._apply(t,(t,e)=>t+e)}sub(t){return this.clone()._apply(t,(t,e)=>t-e)}get shape(){return[this._rows,this._cols]}set shape([t,e,r=(()=>0)]){this._rows=t,this._cols=e,this._data=new Float64Array(t*e);for(let s=0;sr.random),l=h.from(e.col(a)).T.sub(t.dot(n)),_=l.clone();do{const e=t.dot(_),r=l.T.dot(l).entry(0,0)/_.T.dot(e).entry(0,0);n=n.add(_.mult(r));const s=l.sub(e.mult(r)),i=s.T.dot(s).entry(0,0)/l.T.dot(l).entry(0,0);_=s.add(_.mult(i)),l=s}while(Math.abs(l.mean)>s);o=o.concat(n,"horizontal")}return o}static solve(t,e){let{L:r,U:s}="L"in t&&"U"in t?t:h.LU(t),i=r.shape[0],n=e.clone();for(let t=0;t=0;--t){for(let e=i-1;e>t;--e)n.set_entry(0,t,n.entry(0,t)-s.entry(t,e)*n.entry(0,e));n.set_entry(0,t,n.entry(0,t)/s.entry(t,t))}return n}static LU(t){const e=t.shape[0],r=new h(e,e,"zeros"),s=new h(e,e,"identity");for(let i=0;iMath.sqrt(t)),V:n}}}class l{constructor(t){return this._N=624,this._M=397,this._MATRIX_A=2567483615,this._UPPER_MASK=2147483648,this._LOWER_MASK=2147483647,this._mt=new Array(this._N),this._mti=this.N+1,this.seed=t||(new Date).getTime(),this}set seed(t){this._seed=t;let e=this._mt;for(e[0]=t>>>0,this._mti=1;this._mti>>30;e[t]=(1812433253*((4294901760&r)>>>16)<<16)+1812433253*(65535&r)+t,e[t]>>>=0}}get seed(){return this._seed}get random(){return this.random_int*(1/4294967296)}get random_int(){let t,e=new Array(0,this._MATRIX_A);if(this._mti>=this._N){let r;this._mti==this._N+1&&(this.seed=5489);let s=this._N-this._M,i=this._M-this._N;for(r=0;r>>1^e[1&t];for(;r>>1^e[1&t];t=this._mt[this._N-1]&this._UPPER_MASK|this._mt[0]&this._LOWER_MASK,this._mt[this._N-1]=this._mt[this._M-1]^t>>>1^e[1&t],this._mti=0}return t=this._mt[this._mti+=1],t^=t>>>11,t^=t<<7&2636928640,t^=t<<15&4022730752,t^=t>>>18,t>>>0}choice(t,e){if(t instanceof h){let[r,s]=t.shape;if(e>r)throw"n bigger than A!";let i=new Array(e),n=o(0,r-1);for(let t=0,r=n.length;tt.row(e))}if(Array.isArray(t)||t instanceof Float64Array){let r=t.length;if(e>r)throw"n bigger than A!";let s=new Array(e),i=o(0,r-1);for(let t=0,r=i.length;tt[e])}}static choice(t,e,r=19870307){let[s,i]=t.shape;if(e>s)throw"n bigger than A!";let n=new l(r),a=new Array(e),h=o(0,s-1);for(let t=0,r=h.length;tt.row(e))}}class _{constructor(t=null,e=(t=>t),r="min"){return t?_.heapify(t,e,r):(this._accessor=e,this._container=[],this._comparator="min"==r?(t,e)=>tt>e:r,this)}static heapify(t,e=(t=>t),r="min"){const s=new _(null,e,r),i=s._container;for(const r of t)i.push({element:r,value:e(r)});for(let e=Math.floor(t.length/2-1);e>=0;--e)s._heapify_down(e);return s}_swap(t,e){const r=this._container;[r[e],r[t]]=[r[t],r[e]]}_heapify_up(){const t=this._container;let e=t.length-1;for(;e>0;){let r=Math.floor((e-1)/2);if(!this._comparator(t[e].value,t[r].value))break;this._swap(r,e),e=r}}push(t){const e={element:t,value:this._accessor(t)};return this._container.push(e),this._heapify_up(),this}_heapify_down(t=0){const e=this._container,r=this._comparator,s=e.length;let i=2*t+1,n=2*t+2,o=t;if(o>s)throw"index higher than length";i0?this._container[0]:null}*iterate(){for(let t=0,e=this._container.length;tthis._comparator(t,e)?-1:0)}data(){return this._container.map(t=>t.element)}raw_data(){return this._container}get length(){return this._container.length}get empty(){return 0===this.length}}class c{constructor(t=null,r=e){return this._Node=class{constructor(t,e=null,r=null,s=null){this.pivot=t,this.child1=e,this.child2=r,this.radius=s}},this._Leaf=class{constructor(t){this.points=t}},this._metric=r,t&&this.add(t),this}add(t){return t=t.map((t,e)=>({index:e,element:t})),this._root=this._construct(t),this}_construct(t){if(1===t.length)return new this._Leaf(t);{let e,r=this._greatest_spread(t),s=t.sort((t,e)=>t.element[r]-e.element[r]),i=s.length,n=Math.floor(i/2),o=t[n],a=s.slice(0,n),h=s.slice(n,i),l=Math.max(...t.map(t=>this._metric(o.element,t.element)));return e=a.length>0&&h.length>0?new this._Node(o,this._construct(a),this._construct(h),l):new this._Leaf(t),e}}_greatest_spread(t){let e=t[0].element.length,r=new Array(e);for(let t=0;t{for(let s=0;st[1]-t[0]);let i=0;for(let t=0;ts[i]?t:i;return i}search(t,e=5){return this._search(t,e,new _(null,e=>this._metric(e.element,t),"max"),this._root)}_search(t,e,r,s){if(r.length>=e&&s.pivot&&s.radius&&this._metric(t,s.pivot.element)-s.radius>=r.first.value)return r;if(s.child1&&this._search(t,e,r,s.child1),s.child2&&this._search(t,e,r,s.child2),s.points)for(let t=0,i=s.points.length;tr.length?r.push(i):(r.push(i),r.pop())}return r}}function u(t){const[s,i]=t.shape,n=new h(s,i,"identity"),o=new h(i,i,0);for(let h=0;ht*i[e]));o.set_entry(t,h,s),i=i.map((t,r)=>t-s*e[r])}const l=a(i,e);for(let t=0;tn.random));for(;s--;){let e=_.clone(),i=u(t.dot(a));[a,_]=[i.Q,i.R],r(_.sub(e).diag)/o<1e-12&&(s=0)}return{eigenvalues:_.diag,eigenvectors:a.transpose().to2dArray}}class p{static parameter_list=[];constructor(t,r=2,s=e,i=1212){if(Array.isArray(t))this._type="array",this.X=h.from(t);else{if(!(t instanceof h))throw"no valid type for X";this._type="matrix",this.X=t}return[this._N,this._D]=this.X.shape,this._d=r,this._metric=s,this._seed=i,this._randomizer=new l(i),this._is_initialized=!1,this}parameter(t,e=null){if(-1===this.parameter_list.findIndex(e=>e===t))throw t+" is not a valid parameter!";return e?(this["_"+t]=e,this):this["_"+t]}para(t,e=null){return this.parameter(t,e)}p(t,e=null){return this.parameter(t,e)}transform(){return this.check_init(),this.Y}check_init(){this._is_initialized||"function"!=typeof this.init||(this.init(),this._is_initialized=!0)}get projection(){return"matrix"===this._type?this.Y:this.Y.to2dArray}async transform_async(){return this.transform()}}class d extends p{constructor(t,e=2){return super(t,e),this}transform(){let t=this.X,e=t.shape[1],r=new h(e,e,"center"),s=t.dot(r),i=s.transpose().dot(s),{eigenvectors:n}=f(i,this._d);return n=h.from(n).transpose(),this.Y=t.dot(n),this.Y}}class m extends p{constructor(t,r=2,s=e,i=1212){return super(t,r,s,i),this}transform(){const t=this.X,e=t.shape[0],r=this._metric;let s=[],i=[];for(let t=0;t{let h=0;return ea&&(h=o.entry(a,e)),s[e]+=h,i[a]+=h,n+=h,h}],this._d_X=o,s=s.map(t=>t/e),i=i.map(t=>t/e),n/=e**2;const a=new h(e,e,(t,e)=>o.entry(t,e)-s[t]-i[e]+n),{eigenvectors:l}=f(a,this._d);return this.Y=h.from(l).transpose(),this.projection}get stress(){const t=this.X.shape[0],r=this.Y,s=this._d_X,i=new h;i.shape=[t,t,(t,s)=>te<=s?this._metric(t.row(e),t.row(s)):r.entry(s,e)];let s=[];for(let t=0;t({index:e,distance:t})),i=new _(e,t=>t.distance,"min");s.push(i.toArray().slice(1,this._k+1))}let i=new h(e,e,(t,e)=>{let r=s[t].find(t=>t.index===e);return r?r.distance:1/0});for(let t=0;t{let r=i.entry(t,e);return r=r===1/0?0:r,n[t]+=r,o[e]+=r,a+=r,r});n=n.map(t=>t/e),o=o.map(t=>t/e),a/=e**2;let c=new h(e,e,(t,e)=>l.entry(t,e)-n[t]-o[e]+a),{eigenvectors:u}=f(c,this._d);return this.Y=h.from(u).transpose(),this.projection}parameter(t,e=null){return super.parameter(t,e)}para(t,e=null){return this.parameter(t,e)}p(t,e=null){return this.parameter(t,e)}}class w extends p{static parameter_list=["labels"];constructor(t,r,s=2,i=e,n=1212){return super(t,s,i,n),super.parameter_list=w.parameter_list,this.parameter("labels",r),this}transform(){let t=this.X,[e,r]=t.shape,s=this._labels,i={},n=0;s.forEach((e,r)=>{e in i?(i[e].count++,i[e].rows.push(t.row(r))):i[e]={id:n++,count:1,rows:[t.row(r)]}});let o=t.mean,a=new h(n,r);for(let t in i){let e=h.from(i[t].rows).meanCols;for(let s=0;se[t]-o),n=i[t].count;l=l.add(s.dot(s.transpose()).mult(n))}let _=new h(r,r);for(let t in i){let e=a.row(i[t].id),s=new h(r,1,t=>e[t]),n=i[t].rows;for(let e=0,o=i[t].count;en[e][t]-s.entry(t,0));_=_.add(t.dot(t.transpose()))}}let{eigenvectors:c}=f(_.inverse().dot(l),this.d);return c=h.from(c).transpose(),this.Y=t.dot(c),this.projection}}class g extends p{static parameter_list=["k"];constructor(t,r,s=2,i=e,n=1212){return super(t,s,i,n),super.parameter_list=g.parameter_list,this.parameter("k",r||Math.max(Math.floor(t.shape[0]/10),2)),this}transform(){const t=this.X,e=this._d,[s,n]=t.shape,o=this._k,a=i(t.to2dArray,o,null,this._metric),l=new h(o,1,1),_=new h(s,s);for(let e=0;et.entry(a[e][r].j,s)-t.entry(e,s)),i=s.dot(s.transpose());if(o>n){const t=r(i.diag)/1e3;for(let e=0;et.j)];let i=h.from(r.map(e=>t.row(e)));i=i.dot(a);const _=i.dot(i.transpose()),{eigenvectors:c}=f(_,e),u=h.from(c),p=u.transpose().dot(u).add(1/Math.sqrt(n+1));for(let t=0;tthis._randomizer.random),this}init(t=null){const e=Math.log(this._perplexity),r=this._N,s=this._D,i=this._metric,n=this.X;let o;if(t)o=t;else{o=new h(r,r);for(let t=0;t1e-7&&(c-=e*Math.log(e))}c>e?(s=n,n=i===1/0?2*n:(n+i)/2):(i=n,n=s===-1/0?n/2:(n+s)/2),++_,Math.abs(c-e)<1e-4&&(h=!0),_>=50&&(h=!0)}for(let e=0;e=0&&!h;){h=!0;for(let e=0;e.01&&(h=!1),o[e]-=i*s,a=t(o)}i*=n>=a?1.05:.4,n=a}return o}class b extends p{static parameter_list=["local_connectivity","min_dist"];constructor(t,r=1,s=1,i=2,n=e,o=1212){super(t,i,n,o),super.parameter_list=b.parameter_list,[this._N,this._D]=this.X.shape,this.parameter("local_connectivity",r),this.parameter("min_dist",s),this._iter=0,this._n_neighbors=11,this._spread=1,this._set_op_mix_ratio=1,this._repulsion_strength=1,this._negative_sample_rate=5,this._n_epochs=350,this._initial_alpha=1,this.Y=new h(this._N,this._d,()=>this._randomizer.random)}_find_ab_params(t,e){for(var s=o(0,3*t,300),i=o(0,3*t,300),n=0,a=s.length;ni[r]-function(t,e,r){return 1/(1+e*Math.pow(t,2*r))}(s[r],t[0],t[1]));return Math.sqrt(r(e.map(t=>t*t)))}),[1,1]);return[h,l]}_compute_membership_strengths(t,e,r){for(let s=0,i=t.length;s0&&(o=Math.exp(-n/e[s])),t[s][i].value=o}return t}_smooth_knn_dist(t,e){const r=.001,s=this._local_connectivity,i=1*Math.log2(e),n=[],o=[],a=this.X;let h=[];for(let r=0,i=a.shape[0];r0?Math.exp(-e/_):1}if(Math.abs(r-i)<1e-5)break;r>i?(l=_,_=(a+l)/2):(a=_,l===1/0?_*=2:_=(a+l)/2)}o[t]=_;const c=s.reduce((t,e)=>t+e.value,0)/s.length;if(n[t]>0)o[t]t+e.reduce((t,e)=>t+e.value,0)/e.length);o[t]>r*e&&(o[t]=r*e)}}return{distances:h,sigmas:o,rhos:n}}_fuzzy_simplicial_set(t,r){const s=new c(t.to2dArray,e);let{distances:i,sigmas:n,rhos:o}=this._smooth_knn_dist(s,r);i=this._compute_membership_strengths(i,n,o);let a=new h(t.shape[0],t.shape[0],"zeros");for(let e=0,s=t.shape[0];ee*(t/i));return s=s.map((t,r)=>n[r]>0?Math.round(e/n[r]):t),s}_tocoo(t){const e=[],r=[],s=[],[i,n]=t.shape;for(let o=0;ot*this._negative_sample_rate),this._epoch_of_next_sample=this._epochs_per_sample.slice(),this._epoch_of_next_negative_sample=this._epochs_per_negative_sample.slice();const{rows:r,cols:s}=this._tocoo(this._graph);return this._head=r,this._tail=s,this}set local_connectivity(t){this._local_connectivity=t}get local_connectivity(){return this._local_connectivity}set min_dist(t){this._min_dist=t}get min_dist(){return this._min_dist}transform(t){this.check_init(),t=t||this._n_epochs;for(let e=0;e4?4:t<-4?-4:t}_optimize_layout(t,r,s,i){const{_d:n,_alpha:o,_repulsion_strength:a,_a:h,_b:l,_epochs_per_sample:_,_epochs_per_negative_sample:c,_epoch_of_next_negative_sample:u,_epoch_of_next_sample:f,_clip:p}=this,d=i.length;for(let m=0,y=_.length;m0&&(M=-2*h*l*Math.pow(x,l-1)/(h*Math.pow(x,l)+1));for(let e=0;e0)u=2*a*l/((.01+c)*(h*Math.pow(c,l)+1));else if(y==s)continue;for(let e=0;e0!=t.value).sort((t,e)=>t.value-e.value).forEach((e,r)=>{_.set_entry(t,r,e.element.index),c.set_entry(t,r,e.value)});const u=new Float64Array(o);for(let t=0;t0){const{random_triplets:t,random_weights:e}=this._sample_random_triplets(n,r,u);p=p.concat(t,"vertical"),y=Float64Array.from([...y,...e])}d=p.shape[0];let w=-1/0;for(let t=0;tMath.exp(-(t.entry(s,i)**2)/e[s]/e[r.entry(s,i)]))}_sample_knn_triplets(t,e,r,s){const i=e.shape[0],n=new h(i*r*s,3);for(let o=0;o-t));for(let t=0;t({d:t,i:e})).sort((t,e)=>t.d-e.d).map(t=>t.i)}_rejection_sample(t,e,r){const s=this._randomizer,i=o(0,e-1).filter(t=>r.indexOf(t)<0);return s.choice(i,Math.min(t,i.length-2))}_find_weights(t,e,r,s,i){const n=t.shape[0],o=new Float64Array(n);for(let a=0;a=m){u=1,f=1;for(let e=0;ef&&++p,d+=i[e]/(1+f/u);const y=(i[e]/(u+f))**2;for(let t=0;t150?.5:.3,r=this.C,s=this.vel,i=this.Y.add(s.mult(e)),{grad:n,loss:o,n_viol:a}=this._grad(i);return this.C=o,this.Y=this._update_embedding(i,t,n),this.lr*=r>o+this.tol?1.01:.9,this.Y}_update_embedding(t,e,r){const[s,i]=t.shape,n=e>150?.9:.5,o=this.gain,a=this.vel,h=this.lr;for(let e=0;eo&&(r=o),this._randomizer=new l(n),this._clusters=new Array(o).fill(void 0),this._cluster_medoids=this._get_random_medoids(r),this._is_initialized=!1,this}get_clusters(){const t=this._K,e=this._A;this._is_initialized||this.init(t,this._cluster_medoids);const r=new Array(t).fill().map(()=>new Array);return e.forEach((t,e)=>{r[this._nearest_medoid(t,e).index_nearest].push(e)}),r.medoids=this._cluster_medoids,r}async*generator(){const t=this._max_iter;yield this.get_clusters();let e=!1,r=0;do{e=this._iteration(),yield this.get_clusters()}while(!e&&++rthis._nearest_medoid(t,e)),i=new Array(e).fill(0),n=new Array(e).fill(null);if(t.forEach((o,a)=>{if(r.findIndex(t=>t===a)<0){const r=s[a].distance_nearest,h=new Array(e).fill(-r);t.forEach((t,r)=>{if(a===r)return;const i=this._get_distance(r,a,t,o),{index_nearest:n,distance_nearest:l,distance_second:_}=s[r];if(h[n]+=Math.min(i,_)-l,i[t,e]).filter(([t,e])=>t{t=0)return!0;for(;Math.min(...i)<0;){const e=i.map((t,e)=>[t,e]).sort(([t],[e])=>t-e)[0][1];0==r.filter(t=>t==n[e]).length&&(r[e]=n[e]),i[e]=0,i.map((t,e)=>[t,e]).filter(([t])=>t<0).forEach(([n,o])=>{const a=t[o];let h=0;t.forEach((t,i)=>{r.findIndex(t=>t!=o&&t==i)>=0||e!=o&&(s[i].index_nearest===r[o]?h+=Math.min(this._get_distance(i,o,t,a),s[i].distance_second)-s[i].distance_nearest:h+=Math.min(this._get_distance(i,o,t,a)-s[i].distance_nearest,0))}),i[o]=h})}return this._cluster_medoids=r,!1}_get_distance(t,e,r=null,s=null){if(t===e)return 0;const i=this._distance_matrix,n=this._A,o=this._metric;let a=i.entry(t,e);return 0===a&&(a=o(r||n[t],s||n[e]),i.set_entry(t,e,a),i.set_entry(e,t,a)),a}_nearest_medoid(t,e){const r=this._cluster_medoids,s=this._A,[i,n]=r.map((r,i)=>{const n=s[r];return[this._get_distance(e,r,t,n),i]}).sort((t,e)=>t[0]-e[0]);return{distance_nearest:i[0],index_nearest:i[1],distance_second:n[0],index_second:n[1]}}init(t,e){t||(t=this._K),e||(e=this._get_random_medoids(t));const r=this._max_iter;let s=!1,i=0;do{s=this._iteration()}while(!s&&++ih.findIndex(e=>e===t)<0),n);for(let e=0;ethis._get_distance(n,t,a)));l<0&&(s+=l)}s{_.set_entry(e,t,1)});const u=new t(h.from(l.map(t=>r.row(t)))).transform(),f=r.to2dArray,p=new e(f,o),d=new h(s,s,"I"),y=-1/i;f.forEach((t,e)=>{for(const{index:r}of p.search(t,i).iterate())e!==r&&d.set_entry(e,r,y)});const w=d.concat(_,"vertical"),g=new h(s,n,"zeros").concat(u,"vertical");return this._A=w,this._b=g,this._is_initialized=!0,this}transform(){this._is_initialized||this.init();const t=this._A,e=t.T,r=this._b,s=e.dot(t),i=e.dot(r);return this.Y=h.solve_CG(s,i,this._randomizer),this.projection}}t.BallTree=c,t.FASTMAP=class extends p{constructor(t,r=2,s=e,i=1212){return super(t,r,s,i),this._col=-1,this}_choose_distant_objects(t){const e=this.X.shape[0];let r=this._randomizer.random_int%e-1,s=null,i=-1/0;for(let n=0;ni&&(i=e,s=n)}i=-1/0;for(let n=0;ni&&(i=e,r=n)}return[r,s,i]}transform(){const t=this.X,e=t.shape[0],r=this._d,s=this._metric,i=new h(e,r);let n=(e,r)=>s(t.row(e),t.row(r)),o=n;for(;this._colMath.sqrt(o(e,r)**2-(i.entry(e,t)-i.entry(r,t))**2)}}return this.Y=i,this.projection}},t.Heap=_,t.Hierarchical_Clustering=class{constructor(t,r="single",s=e){return this._id=0,this._matrix=t,this._metric=s,this._linkage=r,this.init(),this.root=this.do(),this}get_clusters(t,e="distance"){let r,s=[];switch(e){case"distance":r=t=>t.dist;break;case"depth":r=t=>t.depth;break;default:throw"invalid type"}return this._traverse(this.root,r,t,s),s}_traverse(t,e,r,s){e(t)<=r?s.push(t.leaves()):(this._traverse(t.left,e,r,s),this._traverse(t.right,e,r,s))}init(){const t=this._metric,e=this._matrix,r=this._n=e.shape[0],s=this._d_min=new Float64Array(r),i=this._distance_matrix=new Array(r);for(let n=0;ni[n][o]&&(s[n]=o)}const n=this._clusters=new Array(r),o=this._c_size=new Uint16Array(r);for(let t=0;tr[h][e]&&(r[e][a]=r[a][e]=r[h][e]);break;case"complete":r[a][e]o&&(r=o),this._randomizer=new l(i),this._clusters=new Array(o).fill(void 0),this._cluster_centroids=this._get_random_centroids(r),n&&this.init(r,this._cluster_centroids),this}get_clusters(){const t=this._K,e=this._clusters,r=new Array(t).fill().map(()=>new Array);return e.forEach((t,e)=>r[t].push(e)),r}_furthest_point(t,e){const r=this._matrix,s=this._metric;let i=t.length;return _.heapify(e,e=>{const n=r.row(e);let o=0;for(let e=0;e-1==h.indexOf(t)),l),o=this._furthest_point(i.slice(0,e),t);h.push(o),i[e]=s.row(o)}return i}_iteration(t){const e=t.length,r=this._N,s=this._D,i=this._matrix,n=this._metric,o=this._clusters;let a=!1;for(let s=0;st/e)}}init(t,e){t||(t=this._K),e||(e=this._get_random_centroids(t));let r=!1;do{const t=this._iteration(e);e=t.cluster_centroids,r=t.clusters_changed}while(r)}},t.KMedoids=N,t.LDA=w,t.LLE=g,t.LSP=j,t.LTSA=A,t.MDS=m,t.Matrix=h,t.OPTICS=class{constructor(t,r,s,i=e){return this._matrix=t,this._epsilon=r,this._min_points=s,this._metric=i,this._ordered_list=[],this._clusters=[],this._DB=new Array(t.shape[0]).fill(),this.init(),this}init(){const t=this._ordered_list,e=this._matrix,r=e.shape[0],s=this._DB,i=this._clusters;let n=this._cluster_index=0;for(let t=0;tt.reachability_distance,"min");this._update(e,t),this._expand_cluster(t,i[n])}}_get_neighbors(t){if("neighbors"in t)return t.neighbors;const e=this._DB,r=this._metric,s=this._epsilon,i=[];for(const n of e)n.index!=t.index&&r(t.element,n.element)t.element==n)<0?(n.reachability_distance=i,e.push(n)):it.reachability_distance,"min"))}}_expand_cluster(t,e){const r=this._ordered_list;for(;!t.empty;){const s=t.pop().element;s.neighbors=this._get_neighbors(s),s.processed=!0,e.push(s.index),r.push(s),null!=this._core_distance(s)&&(this._update(s,t),this._expand_cluster(t,e))}}get_clusters(){const t=[],e=[],r=this._min_points;for(const s of this._clusters)s.length=Math.abs(e)?s+=r-n+e:s+=e-n+r,r=n}return r+s}function s(t,e){if(t.length!=e.length)return;let s=t.length,i=new Array(s);for(let r=0;r({i:t,j:r,distance:a[t][r]})).sort((t,e)=>t.distance-e.distance).slice(1,r+1);return a}function n(t,r=e){if(void 0===r)return;let s=t.length,i=new Array(s);for(let t=0;t=0;--i)s[i]=(i*e+(r-i)*t)/r;return s}function a(t,r=e){let s=null;if(t instanceof h){let[e,r]=t.shape;if(1===e)s=t.row(0);else{if(1!==r)throw"matrix must be 1d!";s=t.col(0)}}else s=t;let i=s.length,n=new Array(i);return n.fill(0),r(s,n)}class h{constructor(t=null,e=null,r=null){if(this._rows=t,this._cols=e,this._data=null,t&&e){if(!r)return this._data=new Float64Array(t*e),this;if("function"==typeof r){this._data=new Float64Array(t*e);for(let s=0;s(e===r?1:0)-1/t;for(let s=0;st[r]);if("col"===e)return new h(r,1,e=>t[e]);if("diag"===e)return new h(r,r,(e,r)=>e==r?t[e]:0);throw"1d array has NaN entries"}if(Array.isArray(t[0])||t[0]instanceof Float64Array){let e=t[0].length;for(let s=0;st[e][r])}}}row(t){let e=new Array(this._cols);for(let r=0;rthis.entry(e,t))}get T(){return this.transpose()}inverse(){const t=this._rows,e=this._cols;let r=new h(t,2*e,(t,r)=>r>=e?t===r-e?1:0:this.entry(t,r)),s=0,i=0;for(;s=0;--s){let t=r.entry(s,s);for(let i=0;ir.entry(t,s+e))}dot(t){if(t instanceof h){let e=this;if(e.shape[1]!==t.shape[0])throw`A.dot(B): A is a ${e.shape.join(" x ")}-Matrix, B is a ${t.shape.join(" x ")}-Matrix: \n A has ${e.shape[1]} cols and B ${t.shape[0]} rows. \n Must be equal!`;let s=e.shape[1];return new h(e.shape[0],t.shape[1],(i,n)=>{let o=e.row(i),a=t.col(n);for(let t=0;te*t[i]));return s}throw"B must be Matrix or Array"}outer(t){let e=this,r=e._data.length;if(r!=t._data.length)return;let s=new h;return s.shape=[r,r,(r,i)=>r<=i?e._data[r]*t._data[i]:s.entry(i,r)],s}concat(t,e="horizontal"){const r=this,[s,i]=r.shape,[n,o]=t.shape;if("horizontal"==e){if(s!=n)throw`A.concat(B, "horizontal"): A and B need same number of rows, A has ${s} rows, B has ${n} rows.`;const e=new h(s,i+o,"zeros");return e.set_block(0,0,r),e.set_block(0,i,t),e}if("vertical"==e){if(i!=o)throw`A.concat(B, "vertical"): A and B need same number of columns, A has ${i} columns, B has ${o} columns.`;const e=new h(s+n,i,"zeros");return e.set_block(0,0,r),e.set_block(s,0,t),e}if("diag"==e){const e=new h(s+n,i+o,"zeros");return e.set_block(0,0,r),e.set_block(s,i,t),e}throw`type must be "horizontal" or "vertical", but type is ${e}!`}set_block(t,e,r){let[s,i]=r.shape;for(let n=0;nthis._rows))for(let s=0;sthis._cols||this.set_entry(n+t,s+e,r.entry(n,s));return this}get_block(t,e,r=null,s=null){const[i,n]=this.shape;if(s=s||n,(r=r||i)<=t||s<=e)throw`\n end_row must be greater than start_row, and \n end_col must be greater than start_col, but\n end_row = ${r}, start_row = ${t}, end_col = ${s}, and start_col = ${e}!`;const o=new h(r-t,s-e,"zeros");for(let i=t,n=0;it[r])}_apply_colwise_array(t,e){const r=this._data,[s,i]=this.shape;for(let n=0;nt*e)}divide(t){return this.clone()._apply(t,(t,e)=>t/e)}add(t){return this.clone()._apply(t,(t,e)=>t+e)}sub(t){return this.clone()._apply(t,(t,e)=>t-e)}get shape(){return[this._rows,this._cols]}set shape([t,e,r=(()=>0)]){this._rows=t,this._cols=e,this._data=new Float64Array(t*e);for(let s=0;sr.random),l=h.from(e.col(a)).T.sub(t.dot(n)),_=l.clone();do{const e=t.dot(_),r=l.T.dot(l).entry(0,0)/_.T.dot(e).entry(0,0);n=n.add(_.mult(r));const s=l.sub(e.mult(r)),i=s.T.dot(s).entry(0,0)/l.T.dot(l).entry(0,0);_=s.add(_.mult(i)),l=s}while(Math.abs(l.mean)>s);o=o.concat(n,"horizontal")}return o}static solve(t,e){let{L:r,U:s}="L"in t&&"U"in t?t:h.LU(t),i=r.shape[0],n=e.clone();for(let t=0;t=0;--t){for(let e=i-1;e>t;--e)n.set_entry(0,t,n.entry(0,t)-s.entry(t,e)*n.entry(0,e));n.set_entry(0,t,n.entry(0,t)/s.entry(t,t))}return n}static LU(t){const e=t.shape[0],r=new h(e,e,"zeros"),s=new h(e,e,"identity");for(let i=0;iMath.sqrt(t)),V:n}}}class l{constructor(t){return this._N=624,this._M=397,this._MATRIX_A=2567483615,this._UPPER_MASK=2147483648,this._LOWER_MASK=2147483647,this._mt=new Array(this._N),this._mti=this.N+1,this.seed=t||(new Date).getTime(),this}set seed(t){this._seed=t;let e=this._mt;for(e[0]=t>>>0,this._mti=1;this._mti>>30;e[t]=(1812433253*((4294901760&r)>>>16)<<16)+1812433253*(65535&r)+t,e[t]>>>=0}}get seed(){return this._seed}get random(){return this.random_int*(1/4294967296)}get random_int(){let t,e=new Array(0,this._MATRIX_A);if(this._mti>=this._N){let r;this._mti==this._N+1&&(this.seed=5489);let s=this._N-this._M,i=this._M-this._N;for(r=0;r>>1^e[1&t];for(;r>>1^e[1&t];t=this._mt[this._N-1]&this._UPPER_MASK|this._mt[0]&this._LOWER_MASK,this._mt[this._N-1]=this._mt[this._M-1]^t>>>1^e[1&t],this._mti=0}return t=this._mt[this._mti+=1],t^=t>>>11,t^=t<<7&2636928640,t^=t<<15&4022730752,t^=t>>>18,t>>>0}choice(t,e){if(t instanceof h){let[r,s]=t.shape;if(e>r)throw"n bigger than A!";let i=new Array(e),n=o(0,r-1);for(let t=0,r=n.length;tt.row(e))}if(Array.isArray(t)||t instanceof Float64Array){let r=t.length;if(e>r)throw"n bigger than A!";let s=new Array(e),i=o(0,r-1);for(let t=0,r=i.length;tt[e])}}static choice(t,e,r=19870307){let[s,i]=t.shape;if(e>s)throw"n bigger than A!";let n=new l(r),a=new Array(e),h=o(0,s-1);for(let t=0,r=h.length;tt.row(e))}}class _{constructor(t=null,e=(t=>t),r="min"){return t?_.heapify(t,e,r):(this._accessor=e,this._container=[],this._comparator="min"==r?(t,e)=>tt>e:r,this)}static heapify(t,e=(t=>t),r="min"){const s=new _(null,e,r),i=s._container;for(const r of t)i.push({element:r,value:e(r)});for(let e=Math.floor(t.length/2-1);e>=0;--e)s._heapify_down(e);return s}_swap(t,e){const r=this._container;[r[e],r[t]]=[r[t],r[e]]}_heapify_up(){const t=this._container;let e=t.length-1;for(;e>0;){let r=Math.floor((e-1)/2);if(!this._comparator(t[e].value,t[r].value))break;this._swap(r,e),e=r}}push(t){const e={element:t,value:this._accessor(t)};return this._container.push(e),this._heapify_up(),this}_heapify_down(t=0){const e=this._container,r=this._comparator,s=e.length;let i=2*t+1,n=2*t+2,o=t;if(o>s)throw"index higher than length";i0?this._container[0]:null}*iterate(){for(let t=0,e=this._container.length;tthis._comparator(t,e)?-1:0)}data(){return this._container.map(t=>t.element)}raw_data(){return this._container}get length(){return this._container.length}get empty(){return 0===this.length}}class c{constructor(t=null,r=e){return this._Node=class{constructor(t,e=null,r=null,s=null){this.pivot=t,this.child1=e,this.child2=r,this.radius=s}},this._Leaf=class{constructor(t){this.points=t}},this._metric=r,t&&this.add(t),this}add(t){return t=t.map((t,e)=>({index:e,element:t})),this._root=this._construct(t),this}_construct(t){if(1===t.length)return new this._Leaf(t);{let e,r=this._greatest_spread(t),s=t.sort((t,e)=>t.element[r]-e.element[r]),i=s.length,n=Math.floor(i/2),o=t[n],a=s.slice(0,n),h=s.slice(n,i),l=Math.max(...t.map(t=>this._metric(o.element,t.element)));return e=a.length>0&&h.length>0?new this._Node(o,this._construct(a),this._construct(h),l):new this._Leaf(t),e}}_greatest_spread(t){let e=t[0].element.length,r=new Array(e);for(let t=0;t{for(let s=0;st[1]-t[0]);let i=0;for(let t=0;ts[i]?t:i;return i}search(t,e=5){return this._search(t,e,new _(null,e=>this._metric(e.element,t),"max"),this._root)}_search(t,e,r,s){if(r.length>=e&&s.pivot&&s.radius&&this._metric(t,s.pivot.element)-s.radius>=r.first.value)return r;if(s.child1&&this._search(t,e,r,s.child1),s.child2&&this._search(t,e,r,s.child2),s.points)for(let t=0,i=s.points.length;tr.length?r.push(i):(r.push(i),r.pop())}return r}}function u(t){const[s,i]=t.shape,n=new h(s,i,"identity"),o=new h(i,i,0);for(let h=0;ht*i[e]));o.set_entry(t,h,s),i=i.map((t,r)=>t-s*e[r])}const l=a(i,e);for(let t=0;tn.random));for(;s--;){let e=_.clone(),i=u(t.dot(a));[a,_]=[i.Q,i.R],r(_.sub(e).diag)/o<1e-12&&(s=0)}return{eigenvalues:_.diag,eigenvectors:a.transpose().to2dArray}}class p{static parameter_list=[];constructor(t,r=2,s=e,i=1212){if(Array.isArray(t))this._type="array",this.X=h.from(t);else{if(!(t instanceof h))throw"no valid type for X";this._type="matrix",this.X=t}return[this._N,this._D]=this.X.shape,this._d=r,this._metric=s,this._seed=i,this._randomizer=new l(i),this._is_initialized=!1,this}parameter(t,e=null){if(-1===this.parameter_list.findIndex(e=>e===t))throw t+" is not a valid parameter!";return e?(this["_"+t]=e,this):this["_"+t]}para(t,e=null){return this.parameter(t,e)}p(t,e=null){return this.parameter(t,e)}transform(){return this.check_init(),this.Y}check_init(){this._is_initialized||"function"!=typeof this.init||(this.init(),this._is_initialized=!0)}get projection(){return"matrix"===this._type?this.Y:this.Y.to2dArray}async transform_async(){return this.transform()}}class d extends p{constructor(t,e=2){return super(t,e),this}transform(){let t=this.X,e=t.shape[1],r=new h(e,e,"center"),s=t.dot(r),i=s.transpose().dot(s),{eigenvectors:n}=f(i,this._d);return n=h.from(n).transpose(),this.Y=t.dot(n),this.Y}}class m extends p{constructor(t,r=2,s=e,i=1212){return super(t,r,s,i),this}transform(){const t=this.X,e=t.shape[0],r=this._metric;let s=[],i=[];for(let t=0;t{let h=0;return ea&&(h=o.entry(a,e)),s[e]+=h,i[a]+=h,n+=h,h}],this._d_X=o,s=s.map(t=>t/e),i=i.map(t=>t/e),n/=e**2;const a=new h(e,e,(t,e)=>o.entry(t,e)-s[t]-i[e]+n),{eigenvectors:l}=f(a,this._d);return this.Y=h.from(l).transpose(),this.projection}get stress(){const t=this.X.shape[0],r=this.Y,s=this._d_X,i=new h;i.shape=[t,t,(t,s)=>te<=s?this._metric(t.row(e),t.row(s)):r.entry(s,e)];let s=[];for(let t=0;t({index:e,distance:t})),i=new _(e,t=>t.distance,"min");s.push(i.toArray().slice(1,this._k+1))}let i=new h(e,e,(t,e)=>{let r=s[t].find(t=>t.index===e);return r?r.distance:1/0});for(let t=0;t{let r=i.entry(t,e);return r=r===1/0?0:r,n[t]+=r,o[e]+=r,a+=r,r});n=n.map(t=>t/e),o=o.map(t=>t/e),a/=e**2;let c=new h(e,e,(t,e)=>l.entry(t,e)-n[t]-o[e]+a),{eigenvectors:u}=f(c,this._d);return this.Y=h.from(u).transpose(),this.projection}parameter(t,e=null){return super.parameter(t,e)}para(t,e=null){return this.parameter(t,e)}p(t,e=null){return this.parameter(t,e)}}class w extends p{static parameter_list=["labels"];constructor(t,r,s=2,i=e,n=1212){return super(t,s,i,n),super.parameter_list=w.parameter_list,this.parameter("labels",r),this}transform(){let t=this.X,[e,r]=t.shape,s=this._labels,i={},n=0;s.forEach((e,r)=>{e in i?(i[e].count++,i[e].rows.push(t.row(r))):i[e]={id:n++,count:1,rows:[t.row(r)]}});let o=t.mean,a=new h(n,r);for(let t in i){let e=h.from(i[t].rows).meanCols;for(let s=0;se[t]-o),n=i[t].count;l=l.add(s.dot(s.transpose()).mult(n))}let _=new h(r,r);for(let t in i){let e=a.row(i[t].id),s=new h(r,1,t=>e[t]),n=i[t].rows;for(let e=0,o=i[t].count;en[e][t]-s.entry(t,0));_=_.add(t.dot(t.transpose()))}}let{eigenvectors:c}=f(_.inverse().dot(l),this.d);return c=h.from(c).transpose(),this.Y=t.dot(c),this.projection}}class g extends p{static parameter_list=["k"];constructor(t,r,s=2,i=e,n=1212){return super(t,s,i,n),super.parameter_list=g.parameter_list,this.parameter("k",r||Math.max(Math.floor(t.shape[0]/10),2)),this}transform(){const t=this.X,e=this._d,[s,n]=t.shape,o=this._k,a=i(t.to2dArray,o,null,this._metric),l=new h(o,1,1),_=new h(s,s);for(let e=0;et.entry(a[e][r].j,s)-t.entry(e,s)),i=s.dot(s.transpose());if(o>n){const t=r(i.diag)/1e3;for(let e=0;et.j)];let i=h.from(r.map(e=>t.row(e)));i=i.dot(a);const _=i.dot(i.transpose()),{eigenvectors:c}=f(_,e),u=h.from(c),p=u.transpose().dot(u).add(1/Math.sqrt(n+1));for(let t=0;tthis._randomizer.random),this}init(t=null){const e=Math.log(this._perplexity),r=this._N,s=this._D,i=this._metric,n=this.X;let o;if(t)o=t;else{o=new h(r,r);for(let t=0;t1e-7&&(c-=e*Math.log(e))}c>e?(s=n,n=i===1/0?2*n:(n+i)/2):(i=n,n=s===-1/0?n/2:(n+s)/2),++_,Math.abs(c-e)<1e-4&&(h=!0),_>=50&&(h=!0)}for(let e=0;e=0&&!h;){h=!0;for(let e=0;e.01&&(h=!1),o[e]-=i*s,a=t(o)}i*=n>=a?1.05:.4,n=a}return o}class b extends p{static parameter_list=["local_connectivity","min_dist"];constructor(t,r=1,s=1,i=2,n=e,o=1212){super(t,i,n,o),super.parameter_list=b.parameter_list,[this._N,this._D]=this.X.shape,this.parameter("local_connectivity",r),this.parameter("min_dist",s),this._iter=0,this._n_neighbors=11,this._spread=1,this._set_op_mix_ratio=1,this._repulsion_strength=1,this._negative_sample_rate=5,this._n_epochs=350,this._initial_alpha=1,this.Y=new h(this._N,this._d,()=>this._randomizer.random)}_find_ab_params(t,e){for(var s=o(0,3*t,300),i=o(0,3*t,300),n=0,a=s.length;ni[r]-function(t,e,r){return 1/(1+e*Math.pow(t,2*r))}(s[r],t[0],t[1]));return Math.sqrt(r(e.map(t=>t*t)))}),[1,1]);return[h,l]}_compute_membership_strengths(t,e,r){for(let s=0,i=t.length;s0&&(o=Math.exp(-n/e[s])),t[s][i].value=o}return t}_smooth_knn_dist(t,e){const r=.001,s=this._local_connectivity,i=1*Math.log2(e),n=[],o=[],a=this.X;let h=[];for(let r=0,i=a.shape[0];r0?Math.exp(-e/_):1}if(Math.abs(r-i)<1e-5)break;r>i?(l=_,_=(a+l)/2):(a=_,l===1/0?_*=2:_=(a+l)/2)}o[t]=_;const c=s.reduce((t,e)=>t+e.value,0)/s.length;if(n[t]>0)o[t]t+e.reduce((t,e)=>t+e.value,0)/e.length);o[t]>r*e&&(o[t]=r*e)}}return{distances:h,sigmas:o,rhos:n}}_fuzzy_simplicial_set(t,r){const s=new c(t.to2dArray,e);let{distances:i,sigmas:n,rhos:o}=this._smooth_knn_dist(s,r);i=this._compute_membership_strengths(i,n,o);let a=new h(t.shape[0],t.shape[0],"zeros");for(let e=0,s=t.shape[0];ee*(t/i));return s=s.map((t,r)=>n[r]>0?Math.round(e/n[r]):t),s}_tocoo(t){const e=[],r=[],s=[],[i,n]=t.shape;for(let o=0;ot*this._negative_sample_rate),this._epoch_of_next_sample=this._epochs_per_sample.slice(),this._epoch_of_next_negative_sample=this._epochs_per_negative_sample.slice();const{rows:r,cols:s}=this._tocoo(this._graph);return this._head=r,this._tail=s,this}set local_connectivity(t){this._local_connectivity=t}get local_connectivity(){return this._local_connectivity}set min_dist(t){this._min_dist=t}get min_dist(){return this._min_dist}transform(t){this.check_init(),t=t||this._n_epochs;for(let e=0;e4?4:t<-4?-4:t}_optimize_layout(t,r,s,i){const{_d:n,_alpha:o,_repulsion_strength:a,_a:h,_b:l,_epochs_per_sample:_,_epochs_per_negative_sample:c,_epoch_of_next_negative_sample:u,_epoch_of_next_sample:f,_clip:p}=this,d=i.length;for(let m=0,y=_.length;m0&&(M=-2*h*l*Math.pow(x,l-1)/(h*Math.pow(x,l)+1));for(let e=0;e0)u=2*a*l/((.01+c)*(h*Math.pow(c,l)+1));else if(y==s)continue;for(let e=0;e0!=t.value).sort((t,e)=>t.value-e.value).forEach((e,r)=>{_.set_entry(t,r,e.element.index),c.set_entry(t,r,e.value)});const u=new Float64Array(o);for(let t=0;t0){const{random_triplets:t,random_weights:e}=this._sample_random_triplets(n,r,u);p=p.concat(t,"vertical"),y=Float64Array.from([...y,...e])}d=p.shape[0];let w=-1/0;for(let t=0;tMath.exp(-(t.entry(s,i)**2)/e[s]/e[r.entry(s,i)]))}_sample_knn_triplets(t,e,r,s){const i=e.shape[0],n=new h(i*r*s,3);for(let o=0;o-t));for(let t=0;t({d:t,i:e})).sort((t,e)=>t.d-e.d).map(t=>t.i)}_rejection_sample(t,e,r){const s=this._randomizer,i=o(0,e-1).filter(t=>r.indexOf(t)<0);return s.choice(i,Math.min(t,i.length-2))}_find_weights(t,e,r,s,i){const n=t.shape[0],o=new Float64Array(n);for(let a=0;a=m){u=1,f=1;for(let e=0;ef&&++p,d+=i[e]/(1+f/u);const y=(i[e]/(u+f))**2;for(let t=0;t150?.5:.3,r=this.C,s=this.vel,i=this.Y.add(s.mult(e)),{grad:n,loss:o,n_viol:a}=this._grad(i);return this.C=o,this.Y=this._update_embedding(i,t,n),this.lr*=r>o+this.tol?1.01:.9,this.Y}_update_embedding(t,e,r){const[s,i]=t.shape,n=e>150?.9:.5,o=this.gain,a=this.vel,h=this.lr;for(let e=0;eo&&(r=o),this._randomizer=new l(n),this._clusters=new Array(o).fill(void 0),this._cluster_medoids=this._get_random_medoids(r),this._is_initialized=!1,this}get_clusters(){const t=this._K,e=this._A;this._is_initialized||this.init(t,this._cluster_medoids);const r=new Array(t).fill().map(()=>new Array);return e.forEach((t,e)=>{r[this._nearest_medoid(t,e).index_nearest].push(e)}),r.medoids=this._cluster_medoids,r}async*generator(){const t=this._max_iter;yield this.get_clusters();let e=!1,r=0;do{e=this._iteration(),yield this.get_clusters()}while(!e&&++rthis._nearest_medoid(t,e)),i=new Array(e).fill(0),n=new Array(e).fill(null);if(t.forEach((o,a)=>{if(r.findIndex(t=>t===a)<0){const r=s[a].distance_nearest,h=new Array(e).fill(-r);t.forEach((t,r)=>{if(a===r)return;const i=this._get_distance(r,a,t,o),{index_nearest:n,distance_nearest:l,distance_second:_}=s[r];if(h[n]+=Math.min(i,_)-l,i[t,e]).filter(([t,e])=>t{t=0)return!0;for(;Math.min(...i)<0;){const e=i.map((t,e)=>[t,e]).sort(([t],[e])=>t-e)[0][1];0==r.filter(t=>t==n[e]).length&&(r[e]=n[e]),i[e]=0,i.map((t,e)=>[t,e]).filter(([t])=>t<0).forEach(([n,o])=>{const a=t[o];let h=0;t.forEach((t,i)=>{r.findIndex(t=>t!=o&&t==i)>=0||e!=o&&(s[i].index_nearest===r[o]?h+=Math.min(this._get_distance(i,o,t,a),s[i].distance_second)-s[i].distance_nearest:h+=Math.min(this._get_distance(i,o,t,a)-s[i].distance_nearest,0))}),i[o]=h})}return this._cluster_medoids=r,!1}_get_distance(t,e,r=null,s=null){if(t===e)return 0;const i=this._distance_matrix,n=this._A,o=this._metric;let a=i.entry(t,e);return 0===a&&(a=o(r||n[t],s||n[e]),i.set_entry(t,e,a),i.set_entry(e,t,a)),a}_nearest_medoid(t,e){const r=this._cluster_medoids,s=this._A,[i,n]=r.map((r,i)=>{const n=s[r];return[this._get_distance(e,r,t,n),i]}).sort((t,e)=>t[0]-e[0]);return{distance_nearest:i[0],index_nearest:i[1],distance_second:n[0],index_second:n[1]}}init(t,e){t||(t=this._K),e||(e=this._get_random_medoids(t));const r=this._max_iter;let s=!1,i=0;do{s=this._iteration()}while(!s&&++ih.findIndex(e=>e===t)<0),n);for(let e=0;ethis._get_distance(n,t,a)));l<0&&(s+=l)}s{_.set_entry(e,t,1)});const u=new t(h.from(l.map(t=>r.row(t)))).transform(),f=r.to2dArray,p=new e(f,o),d=new h(s,s,"I"),y=-1/i;f.forEach((t,e)=>{for(const{index:r}of p.search(t,i).iterate())e!==r&&d.set_entry(e,r,y)});const w=d.concat(_,"vertical"),g=new h(s,n,"zeros").concat(u,"vertical");return this._A=w,this._b=g,this._is_initialized=!0,this}transform(){this._is_initialized||this.init();const t=this._A,e=t.T,r=this._b,s=e.dot(t),i=e.dot(r);return this.Y=h.solve_CG(s,i,this._randomizer),this.projection}}t.BallTree=c,t.FASTMAP=class extends p{constructor(t,r=2,s=e,i=1212){return super(t,r,s,i),this._col=-1,this}_choose_distant_objects(t){const e=this.X.shape[0];let r=this._randomizer.random_int%e-1,s=null,i=-1/0;for(let n=0;ni&&(i=e,s=n)}i=-1/0;for(let n=0;ni&&(i=e,r=n)}return[r,s,i]}transform(){const t=this.X,e=t.shape[0],r=this._d,s=this._metric,i=new h(e,r);let n=(e,r)=>s(t.row(e),t.row(r)),o=n;for(;this._colMath.sqrt(o(e,r)**2-(i.entry(e,t)-i.entry(r,t))**2)}}return this.Y=i,this.projection}},t.Heap=_,t.Hierarchical_Clustering=class{constructor(t,r="single",s=e){return this._id=0,this._matrix=t,this._metric=s,this._linkage=r,this.init(),this.root=this.do(),this}get_clusters(t,e="distance"){let r,s=[];switch(e){case"distance":r=t=>t.dist;break;case"depth":r=t=>t.depth;break;default:throw"invalid type"}return this._traverse(this.root,r,t,s),s}_traverse(t,e,r,s){e(t)<=r?s.push(t.leaves()):(this._traverse(t.left,e,r,s),this._traverse(t.right,e,r,s))}init(){const t=this._metric,e=this._matrix,r=this._n=e.shape[0],s=this._d_min=new Float64Array(r),i=this._distance_matrix=new Array(r);for(let n=0;ni[n][o]&&(s[n]=o)}const n=this._clusters=new Array(r),o=this._c_size=new Uint16Array(r);for(let t=0;tr[h][e]&&(r[e][a]=r[a][e]=r[h][e]);break;case"complete":r[a][e]o&&(r=o),this._randomizer=new l(i),this._clusters=new Array(o).fill(void 0),this._cluster_centroids=this._get_random_centroids(r),n&&this.init(r,this._cluster_centroids),this}get_clusters(){const t=this._K,e=this._clusters,r=new Array(t).fill().map(()=>new Array);return e.forEach((t,e)=>r[t].push(e)),r}_furthest_point(t,e){const r=this._matrix,s=this._metric;let i=t.length;return _.heapify(e,e=>{const n=r.row(e);let o=0;for(let e=0;e-1==h.indexOf(t)),l),o=this._furthest_point(i.slice(0,e),t);h.push(o),i[e]=s.row(o)}return i}_iteration(t){const e=t.length,r=this._N,s=this._D,i=this._matrix,n=this._metric,o=this._clusters;let a=!1;for(let s=0;st/e)}}init(t,e){t||(t=this._K),e||(e=this._get_random_centroids(t));let r=!1;do{const t=this._iteration(e);e=t.cluster_centroids,r=t.clusters_changed}while(r)}},t.KMedoids=N,t.LDA=w,t.LLE=g,t.LSP=j,t.LTSA=A,t.MDS=m,t.Matrix=h,t.OPTICS=class{constructor(t,r,s,i=e){return this._matrix=t,this._epsilon=r,this._min_points=s,this._metric=i,this._ordered_list=[],this._clusters=[],this._DB=new Array(t.shape[0]).fill(),this.init(),this}init(){const t=this._ordered_list,e=this._matrix,r=e.shape[0],s=this._DB,i=this._clusters;let n=this._cluster_index=0;for(let t=0;tt.reachability_distance,"min");this._update(e,t),this._expand_cluster(t,i[n])}return this}_get_neighbors(t){if("neighbors"in t)return t.neighbors;const e=this._DB,r=this._metric,s=this._epsilon,i=[];for(const n of e)n.index!=t.index&&r(t.element,n.element)t.element==n)<0?(n.reachability_distance=i,e.push(n)):it.reachability_distance,"min"))}}_expand_cluster(t,e){const r=this._ordered_list;for(;!t.empty;){const s=t.pop().element;s.neighbors=this._get_neighbors(s),s.processed=!0,e.push(s.index),r.push(s),null!=this._core_distance(s)&&(this._update(s,t),this._expand_cluster(t,e))}}get_clusters(){const t=[],e=[],r=this._min_points;for(const s of this._clusters)s.lengthParameters:

View Source - clustering/OPTICS.js, line 97 + clustering/OPTICS.js, line 98

@@ -766,7 +766,7 @@
Parameters:

View Source - clustering/OPTICS.js, line 138 + clustering/OPTICS.js, line 139

@@ -914,7 +914,7 @@
Parameters:

View Source - clustering/OPTICS.js, line 76 + clustering/OPTICS.js, line 77

@@ -1116,7 +1116,7 @@
Parameters:

View Source - clustering/OPTICS.js, line 112 + clustering/OPTICS.js, line 113

@@ -1209,7 +1209,7 @@

View Source - clustering/OPTICS.js, line 175 + clustering/OPTICS.js, line 176

@@ -1331,7 +1331,7 @@

View Source - clustering/OPTICS.js, line 157 + clustering/OPTICS.js, line 158

diff --git a/docs/clustering_OPTICS.js.html b/docs/clustering_OPTICS.js.html index d6dad05..19790f2 100644 --- a/docs/clustering_OPTICS.js.html +++ b/docs/clustering_OPTICS.js.html @@ -152,6 +152,7 @@

clustering/OPTICS.js

this._expand_cluster(seeds, clusters[cluster_index]); } } + return this; } /** diff --git a/docs/index.html b/docs/index.html index a7a0a43..1e5d920 100644 --- a/docs/index.html +++ b/docs/index.html @@ -101,6 +101,11 @@

DruidJS — A JavaScript Library for Dimensionality Reduction.

+

+

DruidJS is a JavaScript library for dimensionality reduction. +With dimesionality reduction you can project high-dimensional data to a lower dimensionality while keeping method-specific properties of the data. +DruidJS makes it easy to project a dataset with the implemented dimensionality reduction methods.

+



Resources

  • Documentation
  • @@ -140,7 +145,7 @@

    Matrix

        let data = await d3.csv("data.csv");
         let matrix = druid.Matrix.from(data);
         d3.selectAll("datapoints").data(matrix.to2dArray)//...
    -    d3.selectAll("datapoints").data(matrix.iterate_rows)//...
    +    d3.selectAll("datapoints").data(matrix.iterate_rows())//...
         d3.selectAll("datapoints").data(matrix)//...
     

    DR methods