void split_points(final short [][] pnts, IntArrayView inds) { IntFloatPair spl = choose_split(pnts, inds); ((InternalNodeData)node_data).disc_dim = spl.first; ((InternalNodeData)node_data).disc = spl.second; int N = inds.size(); int l = 0; int r = N; while (l!=r) { if (pnts[inds.getFast(l)][((InternalNodeData)node_data).disc_dim] < ((InternalNodeData)node_data).disc) l++; else { r--; int t = inds.getFast(l); inds.setFast(l, inds.getFast(r)); inds.setFast(r, t); } } // If either partition is empty -> vectors identical! if (l==0 || l==N) { l = N/2; } // The vectors are identical, so keep nlogn performance. left = new ShortKDTreeNode(pnts, inds.subView(0, l), rng); ((InternalNodeData)node_data).right = new ShortKDTreeNode(pnts, inds.subView(l, N), rng); }
/** * Get a subview of this view from l1 (inclusive) to r1 (exclusive). * @param l1 start (left) index * @param r1 end (right) index * @return subview */ public IntArrayView subView(int l1, int r1) { if ((l+l1) < 0 || (l+r1)>r) throw new ArrayIndexOutOfBoundsException(); return new IntArrayView(array, l+l1, l+r1); }
@Override public IntArrayView clone() { return new IntArrayView(this.toArray()); } }
@Override public IntLongPair chooseSplit(long[][] pnts, IntArrayView inds, int depth, long[] minBounds, long[] maxBounds) { if (inds.size() < maxBucketSize) return null; final int dim = depth % pnts[0].length; final long[] data = new long[inds.size()]; for (int i = 0; i < data.length; i++) data[i] = pnts[inds.getFast(i)][dim]; final long median = ArrayUtils.quickSelect(data, data.length / 2); return IntLongPair.pair(dim, median); } }
/** * Construct a new node with the given data * * @param pnts the data for the node and its children * @param inds a list of indices that point to the relevant * parts of the pnts array that should be used * @param rng the random number generator */ public LongKDTreeNode(final long [][] pnts, IntArrayView inds, Uniform rng) { this.rng = rng; if (inds.size() > leaf_max_points) { // Internal node node_data = new InternalNodeData(); split_points(pnts, inds); } else { node_data = new LeafNodeData(); ((LeafNodeData)node_data).indices = inds.toArray(); } }
/** * Construct a FloatKDTreeEnsemble with the provided data and * number of trees. * @param pnts the data array * @param ntrees the number of KDTrees in the ensemble * @param seed the seed for the random number generator used in * tree construction */ public FloatKDTreeEnsemble(final float [][] pnts, int ntrees, int seed) { final int N = pnts.length; this.pnts = pnts; this.rng = new Uniform(new MersenneTwister(seed)); // Create inds. IntArrayView inds = new IntArrayView(N); for (int n=0; n<N; ++n) inds.setFast(n, n); // Create trees. trees = new FloatKDTreeNode[ntrees]; for (int t=0; t<ntrees; ++t) { trees[t] = new FloatKDTreeNode(pnts, inds,rng); } }
@Override public IntDoublePair chooseSplit(double[][] pnts, IntArrayView inds, int depth, double[] minBounds, double[] maxBounds) { if(inds.size() < minpts) return null; double[][] subarr = new double[inds.size()][ndims]; for (int i = 0; i < subarr.length; i++) { double[] pnti = pnts[inds.get(i)]; for (int dim = startindex; dim < startindex + ndims; dim++) { subarr[i][dim-startindex] = pnti[dim]; Matrix mean = MatrixUtils.sumCols(mat).times(1./inds.size()); Matrix var = MatrixUtils.sumCols(mat.arrayTimes(mat)).times(1./inds.size()).minus(mean.arrayTimes(mean)); double[] col = mat.getMatrix(0, inds.size()-1, maxDim.first, maxDim.first).transpose().getArray()[0]; double mid = detectionMode.detect(col); return IntDoublePair.pair(maxDim.first+startindex,mid);
@Override public IntShortPair chooseSplit(short[][] pnts, IntArrayView inds, int depth, short[] minBounds, short[] maxBounds) { if (inds.size() < maxBucketSize) return null; final int dim = depth % pnts[0].length; final short[] data = new short[inds.size()]; for (int i = 0; i < data.length; i++) data[i] = pnts[inds.getFast(i)][dim]; final short median = ArrayUtils.quickSelect(data, data.length / 2); return IntShortPair.pair(dim, median); } }
/** * Construct a new node with the given data * * @param pnts the data for the node and its children * @param inds a list of indices that point to the relevant * parts of the pnts array that should be used * @param rng the random number generator */ public DoubleKDTreeNode(final double [][] pnts, IntArrayView inds, Uniform rng) { this.rng = rng; if (inds.size() > leaf_max_points) { // Internal node node_data = new InternalNodeData(); split_points(pnts, inds); } else { node_data = new LeafNodeData(); ((LeafNodeData)node_data).indices = inds.toArray(); } }
/** * Construct a LongKDTreeEnsemble with the provided data and * number of trees. * @param pnts the data array * @param ntrees the number of KDTrees in the ensemble * @param seed the seed for the random number generator used in * tree construction */ public LongKDTreeEnsemble(final long [][] pnts, int ntrees, int seed) { final int N = pnts.length; this.pnts = pnts; this.rng = new Uniform(new MersenneTwister(seed)); // Create inds. IntArrayView inds = new IntArrayView(N); for (int n=0; n<N; ++n) inds.setFast(n, n); // Create trees. trees = new LongKDTreeNode[ntrees]; for (int t=0; t<ntrees; ++t) { trees[t] = new LongKDTreeNode(pnts, inds,rng); } }
@Override public IntDoublePair chooseSplit(double[][] pnts, IntArrayView inds, int depth, double[] minBounds, double[] maxBounds) { if(inds.size() < minpts) return null; double[][] subarr = new double[inds.size()][ndims]; for (int i = 0; i < subarr.length; i++) { double[] pnti = pnts[inds.get(i)]; for (int dim = startindex; dim < startindex + ndims; dim++) { subarr[i][dim-startindex] = pnti[dim]; Matrix mean = MatrixUtils.sumCols(mat).times(1./inds.size()); Matrix var = MatrixUtils.sumCols(mat.arrayTimes(mat)).times(1./inds.size()).minus(mean.arrayTimes(mean)); double[] col = mat.getMatrix(0, inds.size()-1, maxDim.first, maxDim.first).transpose().getArray()[0]; double mid = detectionMode.detect(col); return IntDoublePair.pair(maxDim.first+startindex,mid);
void split_points(final float [][] pnts, IntArrayView inds) { IntFloatPair spl = choose_split(pnts, inds); ((InternalNodeData)node_data).disc_dim = spl.first; ((InternalNodeData)node_data).disc = spl.second; int N = inds.size(); int l = 0; int r = N; while (l!=r) { if (pnts[inds.getFast(l)][((InternalNodeData)node_data).disc_dim] < ((InternalNodeData)node_data).disc) l++; else { r--; int t = inds.getFast(l); inds.setFast(l, inds.getFast(r)); inds.setFast(r, t); } } // If either partition is empty -> vectors identical! if (l==0 || l==N) { l = N/2; } // The vectors are identical, so keep nlogn performance. left = new FloatKDTreeNode(pnts, inds.subView(0, l), rng); ((InternalNodeData)node_data).right = new FloatKDTreeNode(pnts, inds.subView(l, N), rng); }
@Override public IntBytePair chooseSplit(byte[][] pnts, IntArrayView inds, int depth, byte[] minBounds, byte[] maxBounds) { if (inds.size() < maxBucketSize) return null; final int dim = depth % pnts[0].length; final byte[] data = new byte[inds.size()]; for (int i = 0; i < data.length; i++) data[i] = pnts[inds.getFast(i)][dim]; final byte median = ArrayUtils.quickSelect(data, data.length / 2); return IntBytePair.pair(dim, median); } }
/** * Construct a new node with the given data * * @param pnts the data for the node and its children * @param inds a list of indices that point to the relevant * parts of the pnts array that should be used * @param rng the random number generator */ public ShortKDTreeNode(final short [][] pnts, IntArrayView inds, Uniform rng) { this.rng = rng; if (inds.size() > leaf_max_points) { // Internal node node_data = new InternalNodeData(); split_points(pnts, inds); } else { node_data = new LeafNodeData(); ((LeafNodeData)node_data).indices = inds.toArray(); } }
/** * Construct a IntKDTreeEnsemble with the provided data and * number of trees. * @param pnts the data array * @param ntrees the number of KDTrees in the ensemble * @param seed the seed for the random number generator used in * tree construction */ public IntKDTreeEnsemble(final int [][] pnts, int ntrees, int seed) { final int N = pnts.length; this.pnts = pnts; this.rng = new Uniform(new MersenneTwister(seed)); // Create inds. IntArrayView inds = new IntArrayView(N); for (int n=0; n<N; ++n) inds.setFast(n, n); // Create trees. trees = new IntKDTreeNode[ntrees]; for (int t=0; t<ntrees; ++t) { trees[t] = new IntKDTreeNode(pnts, inds,rng); } }
/** * Construct with the given data and splitting strategy * * @param data * the data * @param split * the splitting strategy */ public ByteKDTree(byte[][] data, SplitChooser split) { this.data = data; this.root = new KDTreeNode(data, new IntArrayView(ArrayUtils.range(0, data.length - 1)), split); }
void split_points(final int [][] pnts, IntArrayView inds) { IntFloatPair spl = choose_split(pnts, inds); ((InternalNodeData)node_data).disc_dim = spl.first; ((InternalNodeData)node_data).disc = spl.second; int N = inds.size(); int l = 0; int r = N; while (l!=r) { if (pnts[inds.getFast(l)][((InternalNodeData)node_data).disc_dim] < ((InternalNodeData)node_data).disc) l++; else { r--; int t = inds.getFast(l); inds.setFast(l, inds.getFast(r)); inds.setFast(r, t); } } // If either partition is empty -> vectors identical! if (l==0 || l==N) { l = N/2; } // The vectors are identical, so keep nlogn performance. left = new IntKDTreeNode(pnts, inds.subView(0, l), rng); ((InternalNodeData)node_data).right = new IntKDTreeNode(pnts, inds.subView(l, N), rng); }
@Override public IntDoublePair chooseSplit(double[][] pnts, IntArrayView inds, int depth, double[] minBounds, double[] maxBounds) { if (inds.size() < maxBucketSize) return null; final int dim = depth % pnts[0].length; final double[] data = new double[inds.size()]; for (int i = 0; i < data.length; i++) data[i] = pnts[inds.getFast(i)][dim]; final double median = ArrayUtils.quickSelect(data, data.length / 2); return IntDoublePair.pair(dim, median); } }
/** * Construct a new node with the given data * * @param pnts the data for the node and its children * @param inds a list of indices that point to the relevant * parts of the pnts array that should be used * @param rng the random number generator */ public IntKDTreeNode(final int [][] pnts, IntArrayView inds, Uniform rng) { this.rng = rng; if (inds.size() > leaf_max_points) { // Internal node node_data = new InternalNodeData(); split_points(pnts, inds); } else { node_data = new LeafNodeData(); ((LeafNodeData)node_data).indices = inds.toArray(); } }
/** * Construct a FloatKDTreeEnsemble with the provided data and * number of trees. * @param pnts the data array * @param ntrees the number of KDTrees in the ensemble * @param seed the seed for the random number generator used in * tree construction */ public FloatKDTreeEnsemble(final float [][] pnts, int ntrees, int seed) { final int N = pnts.length; this.pnts = pnts; this.rng = new Uniform(new MersenneTwister(seed)); // Create inds. IntArrayView inds = new IntArrayView(N); for (int n=0; n<N; ++n) inds.setFast(n, n); // Create trees. trees = new FloatKDTreeNode[ntrees]; for (int t=0; t<ntrees; ++t) { trees[t] = new FloatKDTreeNode(pnts, inds,rng); } }