You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
3.3 KiB
Plaintext
140 lines
3.3 KiB
Plaintext
TITLE:: FluidKDTree
|
|
summary:: KD Tree on the server
|
|
categories:: FluidManipulation
|
|
related:: Classes/FluidDataSet
|
|
|
|
DESCRIPTION::
|
|
A server-side K-Dimensional tree for efficient neighbourhood searches of multi-dimensional data.
|
|
|
|
See https://scikit-learn.org/stable/modules/neighbors.html#nearest-neighbor-algorithms for more on KD Trees
|
|
|
|
CLASSMETHODS::
|
|
|
|
METHOD:: new
|
|
Make a new KDTree model for the given server.
|
|
ARGUMENT:: server
|
|
The server on which to make the model.
|
|
|
|
INSTANCEMETHODS::
|
|
|
|
METHOD:: fit
|
|
Build the tree by scanning the points of a LINK::Classes/FluidDataSet::
|
|
|
|
ARGUMENT:: dataset
|
|
The LINK::Classes/FluidDataSet:: of interest. This can either be a data set object itself, or the name of one.
|
|
|
|
ARGUMENT:: action
|
|
A function to run when indexing is complete.
|
|
|
|
|
|
METHOD:: kNearest
|
|
Returns the IDs of the CODE::k:: points nearest to the one passed.
|
|
|
|
ARGUMENT:: buffer
|
|
A LINK::Classes/Buffer:: containing a data point to match against. The number of frames in the buffer must match the dimensionality of the LINK::Classes/FluidDataSet:: the tree was fitted to.
|
|
|
|
ARGUMENT:: k
|
|
The number of neighbours to return.
|
|
|
|
|
|
ARGUMENT:: action
|
|
A function that will run when the query returns, whose argument is an array of point IDs from the tree's LINK::Classes/FluidDataSet::
|
|
|
|
METHOD:: kNearestDist
|
|
Get the distances of the K nearest neighbours to a point.
|
|
|
|
ARGUMENT:: buffer
|
|
A LINK::Classes/Buffer:: containing a data point to match against. The number of frames in the buffer must match the dimensionality of the LINK::Classes/FluidDataSet:: the tree was fitted to.
|
|
|
|
ARGUMENT:: k
|
|
The number of neighbours to search
|
|
|
|
ARGUMENT:: action
|
|
A function that will run when the query returns, whose argument is an array of distances.
|
|
|
|
|
|
EXAMPLES::
|
|
|
|
code::
|
|
|
|
|
|
// Make a dataset of random 23D points
|
|
s.boot;
|
|
(
|
|
fork{
|
|
~ds = FluidDataSet.new(s,\kdtree_help_rand2d);
|
|
d = Dictionary.with(
|
|
*[\cols -> 2,\data -> Dictionary.newFrom(
|
|
100.collect{|i| [i, [ 1.0.linrand,1.0.linrand]]}.flatten)]);
|
|
s.sync;
|
|
~ds.load(d, {~ds.print});
|
|
}
|
|
)
|
|
|
|
// Make a new tree, and fit it to the dataset
|
|
~tree = FluidKDTree(s,numNeighbours:5,lookupDataSet:~ds);
|
|
|
|
//Fit it to the dataset
|
|
~tree.fit(~ds);
|
|
|
|
// Should be 100 points, 2 columns
|
|
~tree.size;
|
|
~tree.cols;
|
|
|
|
|
|
//Return labels of k nearest points to a new point
|
|
(
|
|
~p = [ 1.0.linrand,1.0.linrand ];
|
|
~tree.numNeighbours = 5;
|
|
~tmpbuf = Buffer.loadCollection(s, ~p, 1, {
|
|
~tree.kNearest(~tmpbuf,{ |a|a.postln;~nearest = a;})
|
|
});
|
|
)
|
|
|
|
// Labels of nearest points
|
|
~nearest.postln;
|
|
|
|
// Values
|
|
(
|
|
fork{
|
|
~nearest.do{|n|
|
|
~ds.getPoint(n, ~tmpbuf, {~tmpbuf.getn(0, 2, {|x|x.postln})});
|
|
s.sync;
|
|
}
|
|
}
|
|
)
|
|
//Distances of the nearest points
|
|
~tree.kNearestDist(~tmpbuf, { |a| a.postln });
|
|
::
|
|
|
|
subsection:: Server Side Queries
|
|
|
|
code::
|
|
|
|
(
|
|
~inputPoint = Buffer.alloc(s,2);
|
|
~predictPoint = Buffer.alloc(s,10);
|
|
~pitchingBus = Bus.control;
|
|
~catchingBus = Bus.control;
|
|
)
|
|
|
|
(
|
|
|
|
~tree.inBus_(~pitchingBus).outBus_(~catchingBus).inBuffer_(~inputPoint).outBuffer_(~predictPoint);
|
|
{
|
|
var trig = Impulse.kr(ControlRate.ir/2);
|
|
var point = 2.collect{TRand.kr(0,1,trig)};
|
|
point.collect{|p,i| BufWr.kr([p],~inputPoint,i)};
|
|
Poll.kr(trig,point);
|
|
Out.kr(~pitchingBus.index,[trig]);
|
|
Poll.kr(In.kr(~catchingBus.index),BufRd.kr(1,~predictPoint,Array.iota(5)));
|
|
Silent.ar;
|
|
}.play(~tree.synth,addAction:\addBefore);
|
|
|
|
)
|
|
|
|
|
|
|
|
::
|
|
|