Adding debug methods to KSG estimators to retrieve knn distances

This commit is contained in:
Joseph Lizier 2025-04-01 18:08:38 +11:00
parent 13251a0104
commit fa21f7343a
4 changed files with 137 additions and 10 deletions

View File

@ -19,6 +19,7 @@
package infodynamics.measures.continuous.kraskov;
import java.util.Calendar;
import java.util.PriorityQueue;
import infodynamics.measures.continuous.ConditionalMutualInfoCalculatorMultiVariate;
import infodynamics.measures.continuous.ConditionalMutualInfoMultiVariateCommon;
@ -27,6 +28,7 @@ import infodynamics.utils.KdTree;
import infodynamics.utils.MathsUtils;
import infodynamics.utils.MatrixUtils;
import infodynamics.utils.NearestNeighbourSearcher;
import infodynamics.utils.NeighbourNodeData;
import infodynamics.utils.UnivariateNearestNeighbourSearcher;
import infodynamics.utils.EmpiricalMeasurementDistribution;
import infodynamics.utils.NativeUtils;
@ -910,4 +912,68 @@ public abstract class ConditionalMutualInfoCalculatorMultiVariateKraskov
// public ConditionalMutualInfoCalculatorMultiVariateKraskov clone() {
// return this;
// }
/**
* Debug method to return the k nearest neighbour distances that
* would be utilised for each sample point here.
* Note that this is specifically the max-norm across the three variables, which is used for each
* range search in algorithm 1 (although algorithm 2 would use the max distance
* for each variable within the kNNs in their separate range searches).
*
* @param startTimePoint
* @param numTimePoints
* @return
* @throws Exception
*/
public double[] kNNDistances(int startTimePoint, int numTimePoints) throws Exception {
double[] kNNdistances = new double[numTimePoints];
for (int t = startTimePoint; t < startTimePoint + numTimePoints; t++) {
// Compute eps for this time step by
// finding the kth closest neighbour for point t:
PriorityQueue<NeighbourNodeData> nnPQ =
kdTreeJoint.findKNearestNeighbours(k, t, dynCorrExclTime);
// First element in the PQ is the kth NN,
// and epsilon = kthNnData.distance
NeighbourNodeData kthNnData = nnPQ.poll();
kNNdistances[t - startTimePoint] = kthNnData.distance;
}
return kNNdistances;
}
/**
* Debug method to return the k nearest neighbour distances that
* would be utilised in {@link #computeLocalUsingPreviousObservations(double[][], double[][], double[][])}
* for a cross conditional MI.
* Note that this is specifically the max-norm across the three variables, which is used for each
* range search in algorithm 1 (although algorithm 2 would use the max distance
* for each variable within the kNNs in their separate range searches).
*
* @param startTimePoint
* @param numTimePoints
* @param newVar1Observations
* @param newVar2Observations
* @return
* @throws Exception
*/
public double[] kNNDistancesForNewSamples(int startTimePoint, int numTimePoints,
double[][] newStates1, double[][] newStates2, double[][] newCondStates) throws Exception {
double[] kNNdistances = new double[numTimePoints];
for (int t = startTimePoint; t < startTimePoint + numTimePoints; t++) {
// Compute eps for this time step by
// finding the kth closest neighbour for the new sample:
PriorityQueue<NeighbourNodeData> nnPQ =
kdTreeJoint.findKNearestNeighbours(k,
new double[][] {newStates1[t], newStates2[t], newCondStates[t]});
// First element in the PQ is the kth NN,
// and epsilon = kthNnData.distance
NeighbourNodeData kthNnData = nnPQ.poll();
kNNdistances[t - startTimePoint] = kthNnData.distance;
}
return kNNdistances;
}
}

View File

@ -18,19 +18,13 @@
package infodynamics.measures.continuous.kraskov;
import java.util.Arrays;
import java.util.Calendar;
import java.util.PriorityQueue;
import infodynamics.measures.continuous.ConditionalMutualInfoCalculatorMultiVariate;
import infodynamics.utils.EmpiricalMeasurementDistribution;
import infodynamics.utils.FirstIndexComparatorDouble;
import infodynamics.utils.KdTree;
import infodynamics.utils.MathsUtils;
import infodynamics.utils.MatrixUtils;
import infodynamics.utils.NearestNeighbourSearcher;
import infodynamics.utils.NeighbourNodeData;
import infodynamics.utils.UnivariateNearestNeighbourSearcher;
/**
* <p>Computes the differential conditional mutual information of two multivariate
@ -340,7 +334,7 @@ public class ConditionalMutualInfoCalculatorMultiVariateKraskov1
for (int t = startTimePoint; t < startTimePoint + numTimePoints; t++) {
// Compute eps for this time step by
// finding the kth closest neighbour for point t:
// finding the kth closest neighbour for the new sample:
long methodStartTime = Calendar.getInstance().getTimeInMillis();
PriorityQueue<NeighbourNodeData> nnPQ =
kdTreeJoint.findKNearestNeighbours(k,

View File

@ -1106,5 +1106,72 @@ public abstract class MutualInfoCalculatorMultiVariateKraskov
}
return totalErrors;
}
}
/**
* Debug method to return the k nearest neighbour distances that
* would be utilised for each sample point here.
* Note that this is specifically the max-norm across the two variables, which is used for both
* variables in the range searches in algorithm 1 (although algorithm 2 would use the max distance
* for each variable within the kNNs in their separate range searches).
*
* @param startTimePoint
* @param numTimePoints
* @return
* @throws Exception
*/
public double[] kNNDistances(int startTimePoint, int numTimePoints) throws Exception {
double[] kNNdistances = new double[numTimePoints];
for (int t = startTimePoint; t < startTimePoint + numTimePoints; t++) {
// Compute eps for this time step by
// finding the kth closest neighbour for point t:
PriorityQueue<NeighbourNodeData> nnPQ =
kdTreeJoint.findKNearestNeighbours(k, t, dynCorrExclTime);
// First element in the PQ is the kth NN,
// and epsilon = kthNnData.distance
NeighbourNodeData kthNnData = nnPQ.poll();
kNNdistances[t - startTimePoint] = kthNnData.distance;
}
return kNNdistances;
}
/**
* Debug method to return the k nearest neighbour distances that
* would be utilised in {@link #computeLocalUsingPreviousObservations(double[][], double[][])}
* for a cross MI.
* Note that this is specifically the max-norm across the two variables, which is used for both
* variables in the range searches in algorithm 1 (although algorithm 2 would use the max distance
* for each variable within the kNNs in their separate range searches).
*
* @param startTimePoint
* @param numTimePoints
* @param newVar1Observations
* @param newVar2Observations
* @return
* @throws Exception
*/
public double[] kNNDistancesForNewSamples(int startTimePoint, int numTimePoints,
double[][] newVar1Observations, double[][] newVar2Observations) throws Exception {
double[] kNNdistances = new double[numTimePoints];
for (int t = startTimePoint; t < startTimePoint + numTimePoints; t++) {
// Compute eps for this time step by
// finding the kth closest neighbour for the new sample:
PriorityQueue<NeighbourNodeData> nnPQ =
kdTreeJoint.findKNearestNeighbours(k,
new double[][] {newVar1Observations[t], newVar2Observations[t]});
// First element in the PQ is the kth NN,
// and epsilon = kthNnData.distance
NeighbourNodeData kthNnData = nnPQ.poll();
kNNdistances[t - startTimePoint] = kthNnData.distance;
}
return kNNdistances;
}
}

View File

@ -72,7 +72,7 @@ public class MutualInfoCalculatorMultiVariateKraskov1
double sumNx = 0;
double sumNy = 0;
double sum2xkNNDist = 0;
for (int t = startTimePoint; t < startTimePoint + numTimePoints; t++) {
// Compute eps for this time step by
// finding the kth closest neighbour for point t:
@ -196,7 +196,7 @@ public class MutualInfoCalculatorMultiVariateKraskov1
for (int t = startTimePoint; t < startTimePoint + numTimePoints; t++) {
// Compute eps for this time step by
// finding the kth closest neighbour for point t:
// finding the kth closest neighbour for the new sample:
PriorityQueue<NeighbourNodeData> nnPQ =
kdTreeJoint.findKNearestNeighbours(k,
new double[][] {newVar1Observations[t], newVar2Observations[t]});