Inlining norms in Nearest Neighbour search classes, and adding methods to return Collections of points within ranges

This commit is contained in:
joseph.lizier 2014-10-31 12:02:54 +00:00
parent c47fbda738
commit 32c062f880
3 changed files with 426 additions and 41 deletions

View File

@ -18,7 +18,9 @@
package infodynamics.utils;
import java.util.Collection;
import java.util.PriorityQueue;
import java.util.Vector;
/**
* K-d tree implementation to be used for fast neighbour searching
@ -82,13 +84,6 @@ public class KdTree extends NearestNeighbourSearcher {
*/
protected KdTreeNode rootNode = null;
/**
* Calculator for computing the norms for each variable; defaults
* to a max norm.
*/
protected EuclideanUtils normCalculator;
/**
* Protected class to implement nodes of a k-d tree
*
@ -131,9 +126,7 @@ public class KdTree extends NearestNeighbourSearcher {
* within this data set)
*/
public KdTree(int[] dimensions, double[][][] data) {
normCalculator = new EuclideanUtils(normTypeToUse);
this.originalDataSets = data;
int numObservations = data[0].length;
@ -304,15 +297,100 @@ public class KdTree extends NearestNeighbourSearcher {
@Override
public void setNormType(int normType) {
super.setNormType(normType);
normCalculator.setNormToUse(normTypeToUse);
}
@Override
public void setNormType(String normTypeString) {
super.setNormType(normTypeString);
normCalculator.setNormToUse(normTypeToUse);
}
/**
* Computing the configured norm between vectors x1 and x2.
* Adding here instead of using {@link EuclideanUtils#norm(double[], double[])}
* to attempt speed-up.
* Also hoping this method is inlined by the JVM, but haven't checked this.
*
* @param x1 vector of doubles
* @param x2 vector of doubles
* @return the selected norm
*/
public final static double norm(double[] x1, double[] x2, int normToUse) {
double distance = 0.0;
switch (normToUse) {
case EuclideanUtils.NORM_MAX_NORM:
// Inlined from {@link EuclideanUtils}:
for (int d = 0; d < x1.length; d++) {
double difference = x1[d] - x2[d];
// Take the abs
if (difference < 0) {
difference = -difference;
}
if (difference > distance) {
distance = difference;
}
}
return distance;
// case EuclideanUtils.NORM_EUCLIDEAN_SQUARED:
default:
// Inlined from {@link EuclideanUtils}:
for (int d = 0; d < x1.length; d++) {
double difference = x1[d] - x2[d];
distance += difference * difference;
}
return distance;
}
}
/**
* Computing the configured norm between vectors x1 and x2; if
* it becomes clear that norm will be larger than limit,
* then return Double.POSITIVE_INFINITY immediately.
*
* <p>Adding here instead of using {@link EuclideanUtils#normWithAbort(double[], double[], double)}
* to attempt speed-up.
* Also hoping this method is inlined by the JVM, but haven't checked this.</p>
*
* @param x1 vector 1 of doubles
* @param x2 vector 2 of doubles
* @param limit if it becomes clear that norm will be larger than limit,
* then return Double.POSITIVE_INFINITY immediately.
* @param normToUse which norm to use, as defined by {@link #setNormType(int)}
* @return the selected norm
*/
public final static double normWithAbort(double[] x1, double[] x2,
double limit, int normToUse) {
double distance = 0.0;
switch (normToUse) {
case EuclideanUtils.NORM_MAX_NORM:
// Inlined from {@link EuclideanUtils}:
for (int d = 0; d < x1.length; d++) {
double difference = x1[d] - x2[d];
// Take the abs
if (difference < 0) {
difference = -difference;
}
if (difference > distance) {
if (difference > limit) {
return Double.POSITIVE_INFINITY;
}
distance = difference;
}
}
return distance;
// case EuclideanUtils.NORM_EUCLIDEAN_SQUARED:
default:
// Inlined from {@link EuclideanUtils}:
for (int d = 0; d < x1.length; d++) {
double difference = x1[d] - x2[d];
distance += difference * difference;
if (distance > limit) {
return Double.POSITIVE_INFINITY;
}
}
return distance;
}
}
@Override
public NeighbourNodeData findNearestNeighbour(int sampleIndex) {
if (rootNode == null) {
@ -350,7 +428,7 @@ public class KdTree extends NearestNeighbourSearcher {
data[node.indexOfThisPoint][actualDim];
double absDistOnThisDim;
if (normCalculator.getNormInUse() == EuclideanUtils.NORM_MAX_NORM) {
if (normTypeToUse == EuclideanUtils.NORM_MAX_NORM) {
absDistOnThisDim = (distOnThisDim > 0) ? distOnThisDim : - distOnThisDim;
} else {
// norm type is EuclideanUtils#NORM_EUCLIDEAN_SQUARED
@ -369,16 +447,16 @@ public class KdTree extends NearestNeighbourSearcher {
// For each of our separate (multivariate) variables,
// compute the (specified) norm in that variable's space:
if (currentBest == null) {
norms[v] = normCalculator.norm(
norms[v] = norm(
originalDataSets[v][sampleIndex],
originalDataSets[v][node.indexOfThisPoint]);
originalDataSets[v][node.indexOfThisPoint], normTypeToUse);
} else {
// Distance calculation terminates early with Double.POSITIVE_INFINITY
// if it is clearly larger than currentBest.distance:
norms[v] = normCalculator.normWithAbort(
norms[v] = normWithAbort(
originalDataSets[v][sampleIndex],
originalDataSets[v][node.indexOfThisPoint],
currentBest.distance);
currentBest.distance, normTypeToUse);
}
if (norms[v] > maxNorm) {
maxNorm = norms[v];
@ -472,7 +550,7 @@ public class KdTree extends NearestNeighbourSearcher {
double distOnThisDim = data[sampleIndex][actualDim] -
data[node.indexOfThisPoint][actualDim];
double absDistOnThisDim;
if (normCalculator.getNormInUse() == EuclideanUtils.NORM_MAX_NORM) {
if (normTypeToUse == EuclideanUtils.NORM_MAX_NORM) {
absDistOnThisDim = (distOnThisDim > 0) ? distOnThisDim : - distOnThisDim;
} else {
// norm type is EuclideanUtils#NORM_EUCLIDEAN_SQUARED
@ -495,16 +573,16 @@ public class KdTree extends NearestNeighbourSearcher {
// For each of our separate (multivariate) variables,
// compute the (specified) norm in that variable's space:
if (currentKBest.size() < K) {
norms[v] = normCalculator.norm(
norms[v] = norm(
originalDataSets[v][sampleIndex],
originalDataSets[v][node.indexOfThisPoint]);
originalDataSets[v][node.indexOfThisPoint], normTypeToUse);
} else {
// Distance calculation terminates early with Double.POSITIVE_INFINITY
// if it is clearly larger than currentBest.distance:
norms[v] = normCalculator.normWithAbort(
norms[v] = normWithAbort(
originalDataSets[v][sampleIndex],
originalDataSets[v][node.indexOfThisPoint],
furthestCached.distance);
furthestCached.distance, normTypeToUse);
}
if (norms[v] > maxNorm) {
maxNorm = norms[v];
@ -583,12 +661,15 @@ public class KdTree extends NearestNeighbourSearcher {
}
return countPointsWithinR(sampleIndex, rootNode, 0, r, true);
}
/**
* Count the number of points within radius r of a given sample (sampleIndex),
* in the tree rooted at node (which is at the specified level in the tree).
* Nearest neighbour function to compare to r is a max norm between the
* high-level variables, with norm for each variable being the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*
* @param sampleIndex sample index in the data to find a nearest neighbour
* for
@ -614,7 +695,7 @@ public class KdTree extends NearestNeighbourSearcher {
data[node.indexOfThisPoint][actualDim];
double absDistOnThisDim;
if (normCalculator.getNormInUse() == EuclideanUtils.NORM_MAX_NORM) {
if (normTypeToUse == EuclideanUtils.NORM_MAX_NORM) {
absDistOnThisDim = (distOnThisDim > 0) ? distOnThisDim : - distOnThisDim;
} else {
// norm type is EuclideanUtils#NORM_EUCLIDEAN_SQUARED
@ -634,10 +715,10 @@ public class KdTree extends NearestNeighbourSearcher {
double distForVariableV;
// Distance calculation terminates early with Double.POSITIVE_INFINITY
// if it is clearly larger than r:
distForVariableV = normCalculator.normWithAbort(
distForVariableV = normWithAbort(
originalDataSets[v][sampleIndex],
originalDataSets[v][node.indexOfThisPoint],
r);
r, normTypeToUse);
if ((distForVariableV >= r) &&
!(allowEqualToR && (distForVariableV == r))) {
// We don't fit on this dimension, no point
@ -689,6 +770,145 @@ public class KdTree extends NearestNeighbourSearcher {
return count;
}
@Override
public Collection<NeighbourNodeData> findPointsWithinR(int sampleIndex,
double r, boolean allowEqualToR) {
Vector<NeighbourNodeData> pointsWithinR = new Vector<NeighbourNodeData>();
if (rootNode == null) {
return pointsWithinR;
}
findPointsWithinR(sampleIndex,
rootNode, 0, r, allowEqualToR, pointsWithinR);
return pointsWithinR;
}
@Override
public Collection<NeighbourNodeData> findPointsStrictlyWithinR(
int sampleIndex, double r) {
return findPointsWithinR(sampleIndex, r, false);
}
@Override
public Collection<NeighbourNodeData> findPointsWithinOrOnR(int sampleIndex,
double r) {
return findPointsWithinR(sampleIndex, r, true);
}
/**
* Add to the collection of points within radius r of a given sample (sampleIndex),
* in the tree rooted at node (which is at the specified level in the tree).
* Nearest neighbour function to compare to r is a max norm between the
* high-level variables, with norm for each variable being the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*
* @param sampleIndex sample index in the data to find a nearest neighbour
* for
* @param node node to start searching from in the kd-tree. Cannot be null
* @param level which level we're currently at in the tree
* @param r radius within which to count points
* @param allowEqualToR if true, then count points at radius r also,
* otherwise only those strictly within r
* @param pointsWithinR the collection of points to add to
*/
protected void findPointsWithinR(int sampleIndex,
KdTreeNode node, int level, double r, boolean allowEqualToR,
Collection<NeighbourNodeData> pointsWithinR) {
// Point to the correct array for the data at this level
int currentDim = level % totalDimensions;
double[][] data = dimensionToArray[currentDim];
int actualDim = dimensionToArrayIndex[currentDim];
// Check the distance on this particular dimension
double distOnThisDim = data[sampleIndex][actualDim] -
data[node.indexOfThisPoint][actualDim];
double absDistOnThisDim;
if (normTypeToUse == EuclideanUtils.NORM_MAX_NORM) {
absDistOnThisDim = (distOnThisDim > 0) ? distOnThisDim : - distOnThisDim;
} else {
// norm type is EuclideanUtils#NORM_EUCLIDEAN_SQUARED
// Track the square distance
absDistOnThisDim = distOnThisDim * distOnThisDim;
}
if ((node.indexOfThisPoint != sampleIndex) &&
((absDistOnThisDim < r) ||
( allowEqualToR && (absDistOnThisDim == r)))) {
// Preliminary check says we need to compute the full distance
// to use or at least to check if it should be counted.
boolean withinBounds = true;
double[] norms = new double[originalDataSets.length];
double maxNorm = 0;
for (int v = 0; v < originalDataSets.length; v++) {
// For each of our separate (multivariate) variables,
// compute the (specified) norm in that variable's space:
double distForVariableV;
// Distance calculation terminates early with Double.POSITIVE_INFINITY
// if it is clearly larger than r:
distForVariableV = normWithAbort(
originalDataSets[v][sampleIndex],
originalDataSets[v][node.indexOfThisPoint],
r, normTypeToUse);
if ((distForVariableV >= r) &&
!(allowEqualToR && (distForVariableV == r))) {
// We don't fit on this variable, no point
// checking the others:
withinBounds = false;
break;
}
norms[v] = distForVariableV;
if (distForVariableV > maxNorm) {
maxNorm = distForVariableV;
}
}
if (withinBounds) {
// This node gets counted
pointsWithinR.add(
new NeighbourNodeData(node.indexOfThisPoint,
norms, maxNorm));
}
}
KdTreeNode closestSubTree = null;
KdTreeNode furthestSubTree = null;
// And translate this to which subtree is closer
if (distOnThisDim < 0) {
// We need to search the left tree
closestSubTree = node.leftTree;
furthestSubTree = node.rightTree;
} else {
// We need to search the right tree
closestSubTree = node.rightTree;
furthestSubTree = node.leftTree;
}
// Update the search on that subtree
if (closestSubTree != null) {
findPointsWithinR(sampleIndex, closestSubTree,
level + 1, r, allowEqualToR, pointsWithinR);
}
if ((absDistOnThisDim < r) ||
( allowEqualToR && (distOnThisDim < 0) && (absDistOnThisDim == r))) {
// It's possible we could have a node within (or on) r
// in the other branch as well, so search there too.
// (Note: we only check furthest subtree in the == case
// when it's allowed
// *if* it's the right subtree, as only the right sub-tree
// can have node with distance in this coordinate *equal* to
// that of the current node -- left subtree must be strictly
// less than the coordinate of the current node, so
// distance to any of those points could not be equal.)
if (furthestSubTree != null) {
findPointsWithinR(sampleIndex, furthestSubTree,
level + 1, r, allowEqualToR, pointsWithinR);
}
}
}
/**
* Count the number of points within norms {r1,r2,etc} for each high-level
* variable, for a given
@ -696,6 +916,9 @@ public class KdTree extends NearestNeighbourSearcher {
* excluded from the search.
* Nearest neighbour function to compare to {r1,r2,etc}
* for each variable is the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*
* @param sampleIndex sample index in the data to find a nearest neighbour
* for
@ -719,6 +942,9 @@ public class KdTree extends NearestNeighbourSearcher {
* excluded from the search.
* Nearest neighbour function to compare to {r1,r2,etc}
* for each variable is the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*
* @param sampleIndex sample index in the data to find a nearest neighbour
* for
@ -739,6 +965,9 @@ public class KdTree extends NearestNeighbourSearcher {
* excluded from the search.
* Nearest neighbour function to compare to {r1,r2,etc}
* for each variable is the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*
* @param sampleIndex sample index in the data to find a nearest neighbour
* for
@ -760,6 +989,9 @@ public class KdTree extends NearestNeighbourSearcher {
* The node itself is excluded from the search.
* Nearest neighbour function to compare to {r1,r2,etc}
* for each variable is the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*
* @param sampleIndex sample index in the data to find a nearest neighbour
* for
@ -786,7 +1018,7 @@ public class KdTree extends NearestNeighbourSearcher {
data[node.indexOfThisPoint][actualDim];
double absDistOnThisDim;
if (normCalculator.getNormInUse() == EuclideanUtils.NORM_MAX_NORM) {
if (normTypeToUse == EuclideanUtils.NORM_MAX_NORM) {
absDistOnThisDim = (distOnThisDim > 0) ? distOnThisDim : - distOnThisDim;
} else {
// norm type is EuclideanUtils#NORM_EUCLIDEAN_SQUARED
@ -806,10 +1038,10 @@ public class KdTree extends NearestNeighbourSearcher {
double distForVariableV;
// Distance calculation terminates early with Double.POSITIVE_INFINITY
// if it is clearly larger than rs[v]:
distForVariableV = normCalculator.normWithAbort(
distForVariableV = normWithAbort(
originalDataSets[v][sampleIndex],
originalDataSets[v][node.indexOfThisPoint],
rs[v]);
rs[v], normTypeToUse);
if ((distForVariableV >= rs[v]) &&
!(allowEqualToR && (distForVariableV == rs[v]))) {
// We don't fit on this dimension, no point

View File

@ -18,6 +18,7 @@
package infodynamics.utils;
import java.util.Collection;
import java.util.PriorityQueue;
/**
@ -186,6 +187,9 @@ public abstract class NearestNeighbourSearcher {
* excluded from the search.
* Nearest neighbour function to compare to r is a max norm between the
* high-level variables, with norm for each variable being the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*
* @param sampleIndex sample index in the data to find a nearest neighbour
* for
@ -197,12 +201,36 @@ public abstract class NearestNeighbourSearcher {
public abstract int countPointsWithinR(int sampleIndex, double r,
boolean allowEqualToR);
/**
* Return the collection of points within norm r for a given
* sample index in the data set. The node itself is
* excluded from the search.
* Nearest neighbour function to compare to r is a max norm between the
* high-level variables, with norm for each variable being the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*
* @param sampleIndex sample index in the data to find a nearest neighbour
* for
* @param r radius within which to count points
* @param allowEqualToR if true, then count points at radius r also,
* otherwise only those strictly within r
* @return the collection of points within r.
*/
public abstract Collection<NeighbourNodeData> findPointsWithinR(
int sampleIndex, double r,
boolean allowEqualToR);
/**
* Count the number of points strictly within norm r for a given
* sample index in the data set. The node itself is
* excluded from the search.
* Nearest neighbour function to compare to r is a max norm between the
* high-level variables, with norm for each variable being the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*
* @param sampleIndex sample index in the data to find a nearest neighbour
* for
@ -211,12 +239,32 @@ public abstract class NearestNeighbourSearcher {
*/
public abstract int countPointsStrictlyWithinR(int sampleIndex, double r);
/**
* Return the collection of points strictly within norm r for a given
* sample index in the data set. The node itself is
* excluded from the search.
* Nearest neighbour function to compare to r is a max norm between the
* high-level variables, with norm for each variable being the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*
* @param sampleIndex sample index in the data to find a nearest neighbour
* for
* @param r radius within which to count points
* @return the collection of points within r.
*/
public abstract Collection<NeighbourNodeData> findPointsStrictlyWithinR(int sampleIndex, double r);
/**
* Count the number of points within or at norm r for a given
* sample index in the data set. The node itself is
* excluded from the search.
* Nearest neighbour function to compare to r is a max norm between the
* high-level variables, with norm for each variable being the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*
* @param sampleIndex sample index in the data to find a nearest neighbour
* for
@ -224,4 +272,21 @@ public abstract class NearestNeighbourSearcher {
* @return the count of points within or on r.
*/
public abstract int countPointsWithinOrOnR(int sampleIndex, double r);
/**
* Return the collection of points within or at norm r for a given
* sample index in the data set. The node itself is
* excluded from the search.
* Nearest neighbour function to compare to r is a max norm between the
* high-level variables, with norm for each variable being the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*
* @param sampleIndex sample index in the data to find a nearest neighbour
* for
* @param r radius within which to count points
* @return the collection of points within or on r.
*/
public abstract Collection<NeighbourNodeData> findPointsWithinOrOnR(int sampleIndex, double r);
}

View File

@ -18,7 +18,9 @@
package infodynamics.utils;
import java.util.Collection;
import java.util.PriorityQueue;
import java.util.Vector;
/**
@ -80,17 +82,18 @@ public class UnivariateNearestNeighbourSearcher extends NearestNeighbourSearcher
}
/**
* Computed the configured norm between the unidimensional variables
* Computed the configured norm between the unidimensional variables.
* Hoping this method is inlined by the JVM, but haven't checked this.
*
* @param x1 data point 1
* @param x2 data point 2
* @return the norm
*/
protected double norm(double x1, double x2) {
protected static double norm(double x1, double x2, int normTypeToUse) {
switch (normTypeToUse) {
case EuclideanUtils.NORM_MAX_NORM:
return Math.abs(x1-x2);
case EuclideanUtils.NORM_EUCLIDEAN_SQUARED:
// case EuclideanUtils.NORM_EUCLIDEAN_SQUARED:
default:
double difference = x1 - x2;
return difference * difference;
@ -111,7 +114,7 @@ public class UnivariateNearestNeighbourSearcher extends NearestNeighbourSearcher
// Assumes we have more than 1 data point -- this is
// checked in the constructor for us.
double theNorm = norm(originalDataSet[sampleIndex],
originalDataSet[sortedArrayIndices[1]]);
originalDataSet[sortedArrayIndices[1]], normTypeToUse);
return new NeighbourNodeData(sortedArrayIndices[1],
new double[] {theNorm}, theNorm);
} else if (indexInSortedArray == numObservations - 1) {
@ -119,15 +122,18 @@ public class UnivariateNearestNeighbourSearcher extends NearestNeighbourSearcher
// Assumes we have more than 1 data point -- this is
// checked in the constructor for us.
double theNorm = norm(originalDataSet[sampleIndex],
originalDataSet[sortedArrayIndices[numObservations - 2]]);
originalDataSet[sortedArrayIndices[numObservations - 2]],
normTypeToUse);
return new NeighbourNodeData(sortedArrayIndices[numObservations - 2],
new double[] {theNorm}, theNorm);
} else {
// We need to check candidates on both sides of the data point:
double normAbove = norm(originalDataSet[sampleIndex],
originalDataSet[sortedArrayIndices[indexInSortedArray+1]]);
originalDataSet[sortedArrayIndices[indexInSortedArray+1]],
normTypeToUse);
double normBelow = norm(originalDataSet[sampleIndex],
originalDataSet[sortedArrayIndices[indexInSortedArray-1]]);
originalDataSet[sortedArrayIndices[indexInSortedArray-1]],
normTypeToUse);
if (normAbove < normBelow) {
return new NeighbourNodeData(sortedArrayIndices[indexInSortedArray+1],
new double[] {normAbove}, normAbove);
@ -168,11 +174,13 @@ public class UnivariateNearestNeighbourSearcher extends NearestNeighbourSearcher
double normAbove = (upperCandidate == -1) ?
Double.POSITIVE_INFINITY :
norm(originalDataSet[sampleIndex],
originalDataSet[sortedArrayIndices[upperCandidate]]);
originalDataSet[sortedArrayIndices[upperCandidate]],
normTypeToUse);
double normBelow = (lowerCandidate == -1) ?
Double.POSITIVE_INFINITY :
norm(originalDataSet[sampleIndex],
originalDataSet[sortedArrayIndices[lowerCandidate]]);
originalDataSet[sortedArrayIndices[lowerCandidate]],
normTypeToUse);
NeighbourNodeData nextNearest;
if (normAbove < normBelow) {
nextNearest = new NeighbourNodeData(sortedArrayIndices[upperCandidate],
@ -199,6 +207,9 @@ public class UnivariateNearestNeighbourSearcher extends NearestNeighbourSearcher
* sample index in the data set. The node itself is
* excluded from the search.
* Nearest neighbour function to compare to r is the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*/
public int countPointsWithinR(int sampleIndex, double r, boolean allowEqualToR) {
int count = 0;
@ -207,7 +218,7 @@ public class UnivariateNearestNeighbourSearcher extends NearestNeighbourSearcher
// Check the points with smaller data values first:
for (int i = indexInSortedArray - 1; i >= 0; i--) {
double theNorm = norm(originalDataSet[sampleIndex],
originalDataSet[sortedArrayIndices[i]]);
originalDataSet[sortedArrayIndices[i]], normTypeToUse);
if ((allowEqualToR && (theNorm <= r)) ||
(!allowEqualToR && (theNorm < r))) {
count++;
@ -219,7 +230,7 @@ public class UnivariateNearestNeighbourSearcher extends NearestNeighbourSearcher
// Next check the points with larger data values:
for (int i = indexInSortedArray + 1; i < numObservations; i++) {
double theNorm = norm(originalDataSet[sampleIndex],
originalDataSet[sortedArrayIndices[i]]);
originalDataSet[sortedArrayIndices[i]], normTypeToUse);
if ((allowEqualToR && (theNorm <= r)) ||
(!allowEqualToR && (theNorm < r))) {
count++;
@ -231,24 +242,101 @@ public class UnivariateNearestNeighbourSearcher extends NearestNeighbourSearcher
return count;
}
/**
* Count the number of points within norm r for a given
* sample index in the data set. The node itself is
* excluded from the search.
* Nearest neighbour function to compare to r is the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*/
public Collection<NeighbourNodeData> findPointsWithinR(int sampleIndex, double r, boolean allowEqualToR) {
Vector<NeighbourNodeData> pointsWithinR = new Vector<NeighbourNodeData>();
// Find where this node sits in the sorted array:
int indexInSortedArray = indicesInSortedArray[sampleIndex];
// Check the points with smaller data values first:
for (int i = indexInSortedArray - 1; i >= 0; i--) {
double theNorm = norm(originalDataSet[sampleIndex],
originalDataSet[sortedArrayIndices[i]], normTypeToUse);
if ((allowEqualToR && (theNorm <= r)) ||
(!allowEqualToR && (theNorm < r))) {
pointsWithinR.add(
new NeighbourNodeData(sortedArrayIndices[i],
new double[] {theNorm}, theNorm));
continue;
}
// Else no point checking further points
break;
}
// Next check the points with larger data values:
for (int i = indexInSortedArray + 1; i < numObservations; i++) {
double theNorm = norm(originalDataSet[sampleIndex],
originalDataSet[sortedArrayIndices[i]], normTypeToUse);
if ((allowEqualToR && (theNorm <= r)) ||
(!allowEqualToR && (theNorm < r))) {
pointsWithinR.add(
new NeighbourNodeData(sortedArrayIndices[i],
new double[] {theNorm}, theNorm));
continue;
}
// Else no point checking further points
break;
}
return pointsWithinR;
}
/**
* Count the number of points strictly within norm r for a given
* sample index in the data set. The node itself is
* excluded from the search.
* Nearest neighbour function to compare to r is the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*
*/
public int countPointsStrictlyWithinR(int sampleIndex, double r) {
return countPointsWithinR(sampleIndex, r, false);
}
/**
* Return a collection of points strictly within norm r for a given
* sample index in the data set. The node itself is
* excluded from the search.
* Nearest neighbour function to compare to r is the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*
*/
public Collection<NeighbourNodeData> findPointsStrictlyWithinR(int sampleIndex, double r) {
return findPointsWithinR(sampleIndex, r, false);
}
/**
* Count the number of points within or at norm r for a given
* sample index in the data set. The node itself is
* excluded from the search.
* Nearest neighbour function to compare to r is the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*/
public int countPointsWithinOrOnR(int sampleIndex, double r) {
return countPointsWithinR(sampleIndex, r, true);
}
/**
* Return a collection of points within or at norm r for a given
* sample index in the data set. The node itself is
* excluded from the search.
* Nearest neighbour function to compare to r is the specified norm.
* (If {@link EuclideanUtils#NORM_EUCLIDEAN} was selected, then the supplied
* r should be the required Euclidean norm <b>squared</b>, since we switch it
* to {@link EuclideanUtils#NORM_EUCLIDEAN_SQUARED} internally).
*/
public Collection<NeighbourNodeData> findPointsWithinOrOnR(int sampleIndex, double r) {
return findPointsWithinR(sampleIndex, r, true);
}
}