Altered interal names of kernel width variables to be kernel width, instead of epsilon. This is more intuitive for users.

This commit is contained in:
joseph.lizier 2012-08-07 07:49:23 +00:00
parent 7159ecd4cc
commit 12e6f12147
5 changed files with 91 additions and 70 deletions

View File

@ -8,17 +8,24 @@ import java.util.Hashtable;
/** /**
* Class to maintain probability distribution function for * <p>Class to maintain probability distribution function for
* a single variable, using kernel estimates. * a multivariate set, using kernel estimates.</p>
* *
* <p>
* For more details on kernel estimation for computing probability distribution functions,
* see Kantz and Schreiber (below).
* </p>
* *
* @author Joseph Lizier * @see KernelEstimatorSingleVariate
* @see "H. Kantz and T. Schreiber, 'Nonlinear Time Series Analysis'.
* Cambridge, MA: Cambridge University Press, 1997"
* @author Joseph Lizier, <a href="mailto:joseph.lizier at gmail.com">joseph.lizier at gmail.com</>
* *
*/ */
public class KernelEstimatorMultiVariate implements Cloneable { public class KernelEstimatorMultiVariate implements Cloneable {
protected double[] epsilon = null; protected double[] suppliedKernelWidths = null;
protected double[] epsilonInUse = null; protected double[] kernelWidthsInUse = null;
protected int dimensions = 1; protected int dimensions = 1;
private int[] bins = null; private int[] bins = null;
private boolean usingIntegerIndexBins = true; private boolean usingIntegerIndexBins = true;
@ -107,9 +114,9 @@ public class KernelEstimatorMultiVariate implements Cloneable {
*/ */
public void initialise(int dimensions, double epsilon) { public void initialise(int dimensions, double epsilon) {
this.dimensions = dimensions; this.dimensions = dimensions;
this.epsilon = new double[dimensions]; this.suppliedKernelWidths = new double[dimensions];
for (int d = 0; d < dimensions; d++) { for (int d = 0; d < dimensions; d++) {
this.epsilon[d] = epsilon; this.suppliedKernelWidths[d] = epsilon;
} }
finishInitialisation(); finishInitialisation();
} }
@ -121,9 +128,9 @@ public class KernelEstimatorMultiVariate implements Cloneable {
*/ */
public void initialise(double[] epsilon) { public void initialise(double[] epsilon) {
dimensions = epsilon.length; dimensions = epsilon.length;
this.epsilon = new double[dimensions]; this.suppliedKernelWidths = new double[dimensions];
for (int d = 0; d < dimensions; d++) { for (int d = 0; d < dimensions; d++) {
this.epsilon[d] = epsilon[d]; this.suppliedKernelWidths[d] = epsilon[d];
} }
finishInitialisation(); finishInitialisation();
} }
@ -142,7 +149,7 @@ public class KernelEstimatorMultiVariate implements Cloneable {
multipliers = null; multipliers = null;
rawData = null; rawData = null;
totalObservations = 0; totalObservations = 0;
epsilonInUse = new double[dimensions]; kernelWidthsInUse = new double[dimensions];
} }
/** /**
@ -172,11 +179,11 @@ public class KernelEstimatorMultiVariate implements Cloneable {
// it should expand with the standard deviation. // it should expand with the standard deviation.
// This saves us from normalising all of the incoming data points! // This saves us from normalising all of the incoming data points!
std = MatrixUtils.stdDev(data, d); std = MatrixUtils.stdDev(data, d);
epsilonInUse[d] = epsilon[d] * std; kernelWidthsInUse[d] = suppliedKernelWidths[d] * std;
} else { } else {
epsilonInUse[d] = epsilon[d]; kernelWidthsInUse[d] = suppliedKernelWidths[d];
} }
bins[d] = (int) Math.ceil((max - mins[d]) / epsilonInUse[d]); bins[d] = (int) Math.ceil((max - mins[d]) / kernelWidthsInUse[d]);
if (bins[d] == 0) { if (bins[d] == 0) {
// This means the min and max are exactly the same: // This means the min and max are exactly the same:
// for our purposes this is akin to requiring one bin here. // for our purposes this is akin to requiring one bin here.
@ -196,7 +203,7 @@ public class KernelEstimatorMultiVariate implements Cloneable {
System.out.println("Dim: " + d + " => Max: " + max + ", min: " + mins[d] + System.out.println("Dim: " + d + " => Max: " + max + ", min: " + mins[d] +
", bins: " + bins[d] + ", bins: " + bins[d] +
(normalise ? ", std: " + std : "") + (normalise ? ", std: " + std : "") +
", eps: " + epsilonInUse[d]); ", eps: " + kernelWidthsInUse[d]);
} }
} }
@ -774,7 +781,7 @@ public class KernelEstimatorMultiVariate implements Cloneable {
} }
private int getBinIndex(double value, int dimension) { private int getBinIndex(double value, int dimension) {
int bin = (int) Math.floor((value - mins[dimension]) / epsilonInUse[dimension]); int bin = (int) Math.floor((value - mins[dimension]) / kernelWidthsInUse[dimension]);
// Check for any rounding errors on the bin assignment: // Check for any rounding errors on the bin assignment:
if (bin >= bins[dimension]) { if (bin >= bins[dimension]) {
bin = bins[dimension] - 1; bin = bins[dimension] - 1;
@ -915,7 +922,7 @@ public class KernelEstimatorMultiVariate implements Cloneable {
*/ */
public int stepKernel(double[] observation, double[] candidate) { public int stepKernel(double[] observation, double[] candidate) {
for (int d = 0; d < dimensions; d++) { for (int d = 0; d < dimensions; d++) {
if (Math.abs(observation[d] - candidate[d]) > epsilonInUse[d]) { if (Math.abs(observation[d] - candidate[d]) > kernelWidthsInUse[d]) {
return 0; return 0;
} }
} }

View File

@ -6,17 +6,23 @@ import java.util.Vector;
import java.util.Arrays; import java.util.Arrays;
/** /**
* Class to maintain probability distribution function for * <p>Class to maintain probability distribution function for
* a single variable, using kernel estimates. * a single variable, using kernel estimates.</p>
* *
* <p>
* For more details on kernel estimation for computing probability distribution functions,
* see Kantz and Schreiber (below).
* </p>
* *
* @author Joseph Lizier * @see "H. Kantz and T. Schreiber, 'Nonlinear Time Series Analysis'.
* Cambridge, MA: Cambridge University Press, 1997"
* @author Joseph Lizier, <a href="mailto:joseph.lizier at gmail.com">joseph.lizier at gmail.com</>
* *
*/ */
public class KernelEstimatorSingleVariate { public class KernelEstimatorSingleVariate {
private double epsilon = 0.1; private double suppliedKernelWidth = 0.1;
private double epsilonInUse; private double kernelWidthInUse;
private double min = 0; private double min = 0;
private double max = 0; private double max = 0;
private int bins = 0; private int bins = 0;
@ -72,7 +78,7 @@ public class KernelEstimatorSingleVariate {
* @param epsilon * @param epsilon
*/ */
public void initialise(double epsilon) { public void initialise(double epsilon) {
this.epsilon = epsilon; this.suppliedKernelWidth = epsilon;
sortedObservations = null; sortedObservations = null;
} }
@ -90,14 +96,14 @@ public class KernelEstimatorSingleVariate {
// it should expand with the standard deviation. // it should expand with the standard deviation.
// This saves us from normalising all of the incoming data points! // This saves us from normalising all of the incoming data points!
double std = MatrixUtils.stdDev(data); double std = MatrixUtils.stdDev(data);
epsilonInUse = epsilon * std; kernelWidthInUse = suppliedKernelWidth * std;
} else { } else {
epsilonInUse = epsilon; kernelWidthInUse = suppliedKernelWidth;
} }
// Create the bins // Create the bins
Vector<TimeStampedObservation>[] observations = null; Vector<TimeStampedObservation>[] observations = null;
bins = (int) Math.ceil((max - min) / epsilonInUse); bins = (int) Math.ceil((max - min) / kernelWidthInUse);
if (bins == 0) { if (bins == 0) {
// The max and min are the same. // The max and min are the same.
// Should still have one bin here to put all the data in, // Should still have one bin here to put all the data in,
@ -207,7 +213,7 @@ public class KernelEstimatorSingleVariate {
// are no longer within epsilon of the given value. // are no longer within epsilon of the given value.
int topIndex; int topIndex;
for (topIndex = sortedObservations[bin-1].length; for (topIndex = sortedObservations[bin-1].length;
(topIndex > 0) && (sortedObservations[bin-1][topIndex-1].observation > observation - epsilonInUse); (topIndex > 0) && (sortedObservations[bin-1][topIndex-1].observation > observation - kernelWidthInUse);
topIndex--) { topIndex--) {
// This observation is within epsilon. // This observation is within epsilon.
// Before adding to the count just check if it's a dynamic correlation if required: // Before adding to the count just check if it's a dynamic correlation if required:
@ -233,7 +239,7 @@ public class KernelEstimatorSingleVariate {
int bottomIndex; int bottomIndex;
for (bottomIndex = 0; for (bottomIndex = 0;
(bottomIndex < sortedObservations[bin+1].length) && (bottomIndex < sortedObservations[bin+1].length) &&
(sortedObservations[bin+1][bottomIndex].observation < observation + epsilonInUse); (sortedObservations[bin+1][bottomIndex].observation < observation + kernelWidthInUse);
bottomIndex++) { bottomIndex++) {
// This observation is within epsilon. // This observation is within epsilon.
// Before adding to the count just check if it's a dynamic correlation if required: // Before adding to the count just check if it's a dynamic correlation if required:
@ -256,7 +262,7 @@ public class KernelEstimatorSingleVariate {
} }
private int getBinIndex(double value) { private int getBinIndex(double value) {
int bin = (int) Math.floor((value - min) / epsilonInUse); int bin = (int) Math.floor((value - min) / kernelWidthInUse);
// Check for any rounding errors on the bin assignment: // Check for any rounding errors on the bin assignment:
if (bin >= bins) { if (bin >= bins) {
bin = bins - 1; bin = bins - 1;

View File

@ -13,13 +13,16 @@ import infodynamics.utils.MatrixUtils;
* function on the joint history. * function on the joint history.
* </p> * </p>
* *
* @author Joseph Lizier joseph.lizier at gmail.com * @see KernelEstimatorMultiVariate
* @see "H. Kantz and T. Schreiber, 'Nonlinear Time Series Analysis'.
* Cambridge, MA: Cambridge University Press, 1997"
* @author Joseph Lizier, <a href="mailto:joseph.lizier at gmail.com">joseph.lizier at gmail.com</>
* *
*/ */
public class KernelEstimatorTransferEntropy extends KernelEstimatorMultiVariate { public class KernelEstimatorTransferEntropy extends KernelEstimatorMultiVariate {
private double epsilonSource; private double suppliedKernelWidthSource;
private double epsilonSourceInUse; private double kernelWidthSourceInUse;
private double[] destNext; private double[] destNext;
private double[] source; private double[] source;
@ -42,13 +45,13 @@ public class KernelEstimatorTransferEntropy extends KernelEstimatorMultiVariate
public void initialise(int dimensions, double epsilon) { public void initialise(int dimensions, double epsilon) {
super.initialise(dimensions, epsilon); super.initialise(dimensions, epsilon);
this.epsilonSource = epsilon; this.suppliedKernelWidthSource = epsilon;
} }
public void initialise(int dimensions, double epsilonDest, public void initialise(int dimensions, double epsilonDest,
double epsilonSource) { double epsilonSource) {
super.initialise(dimensions, epsilonDest); super.initialise(dimensions, epsilonDest);
this.epsilonSource = epsilonSource; this.suppliedKernelWidthSource = epsilonSource;
} }
public void setObservations(double[][] destPastVectors, public void setObservations(double[][] destPastVectors,
@ -61,9 +64,9 @@ public class KernelEstimatorTransferEntropy extends KernelEstimatorMultiVariate
if (normalise) { if (normalise) {
double std = MatrixUtils.stdDev(source); double std = MatrixUtils.stdDev(source);
epsilonSourceInUse = epsilonSource * std; kernelWidthSourceInUse = suppliedKernelWidthSource * std;
} else { } else {
epsilonSourceInUse = epsilonSource; kernelWidthSourceInUse = suppliedKernelWidthSource;
} }
this.source = source; this.source = source;
@ -107,7 +110,7 @@ public class KernelEstimatorTransferEntropy extends KernelEstimatorMultiVariate
} }
public void setEpsSource(double epsilonSource) { public void setEpsSource(double epsilonSource) {
this.epsilonSource = epsilonSource; this.suppliedKernelWidthSource = epsilonSource;
} }
/** /**
@ -118,13 +121,13 @@ public class KernelEstimatorTransferEntropy extends KernelEstimatorMultiVariate
*/ */
protected void correlatedPointAddedCallback(int correlatedTimeStep) { protected void correlatedPointAddedCallback(int correlatedTimeStep) {
boolean sourceMatches = false; boolean sourceMatches = false;
if (Math.abs(sourceObs - source[correlatedTimeStep]) <= epsilonSourceInUse) { if (Math.abs(sourceObs - source[correlatedTimeStep]) <= kernelWidthSourceInUse) {
countPastSource++; countPastSource++;
sourceMatches = true; sourceMatches = true;
} }
// The epsilons across the destination variables should all be approximately // The epsilons across the destination variables should all be approximately
// equal, so just use the first one. // equal, so just use the first one.
if (Math.abs(destNextObs - destNext[correlatedTimeStep]) <= epsilonInUse[0]) { if (Math.abs(destNextObs - destNext[correlatedTimeStep]) <= kernelWidthsInUse[0]) {
countNextPast++; countNextPast++;
if (sourceMatches) { if (sourceMatches) {
countNextPastSource++; countNextPastSource++;
@ -139,13 +142,13 @@ public class KernelEstimatorTransferEntropy extends KernelEstimatorMultiVariate
*/ */
protected void correlatedPointRemovedCallback(int removedCorrelatedTimeStep) { protected void correlatedPointRemovedCallback(int removedCorrelatedTimeStep) {
boolean sourceMatches = false; boolean sourceMatches = false;
if (Math.abs(sourceObs - source[removedCorrelatedTimeStep]) <= epsilonSourceInUse) { if (Math.abs(sourceObs - source[removedCorrelatedTimeStep]) <= kernelWidthSourceInUse) {
countPastSource--; countPastSource--;
sourceMatches = true; sourceMatches = true;
} }
// The epsilons across the destination variables should all be approximately // The epsilons across the destination variables should all be approximately
// equal, so just use the first one. // equal, so just use the first one.
if (Math.abs(destNextObs - destNext[removedCorrelatedTimeStep]) <= epsilonInUse[0]) { if (Math.abs(destNextObs - destNext[removedCorrelatedTimeStep]) <= kernelWidthsInUse[0]) {
countNextPast--; countNextPast--;
if (sourceMatches) { if (sourceMatches) {
countNextPastSource--; countNextPastSource--;

View File

@ -6,28 +6,33 @@ package infodynamics.measures.continuous.kernel;
import infodynamics.utils.MatrixUtils; import infodynamics.utils.MatrixUtils;
/** /**
* <p>Kernel estimator for use with the transfer entropy.</p> * <p>Kernel estimator for use with the transfer entropy on
* multivariate source and destination.</p>
* *
* <p>Extends KernelEstimatorMultiVariate, using the super class to manage the history of the destination * <p>Extends KernelEstimatorMultiVariate, using the super class to manage the history of the destination
* variable, and adds the next state and source on top of this. Any calls to the super class methods will only * variable, and adds the next state and source on top of this. Any calls to the super class methods will only
* function on the joint history. * function on the joint history.
* </p> * </p>
* *
* @author Joseph Lizier joseph.lizier at gmail.com * @see KernelEstimatorMultiVariate
* @see KernelEstimatorTransferEntropy
* @see "H. Kantz and T. Schreiber, 'Nonlinear Time Series Analysis'.
* Cambridge, MA: Cambridge University Press, 1997"
* @author Joseph Lizier, <a href="mailto:joseph.lizier at gmail.com">joseph.lizier at gmail.com</>
* *
*/ */
public class KernelEstimatorTransferEntropyMultiVariate extends KernelEstimatorMultiVariate { public class KernelEstimatorTransferEntropyMultiVariate extends KernelEstimatorMultiVariate {
private int sourceDimensions; private int sourceDimensions;
private double[] epsilonSource; private double[] suppliedKernelWidthSource;
private double[] epsilonSourceInUse; private double[] kernelWidthSourceInUse;
// Keep a separate epsilon for the destination next state, just in case // Keep a separate epsilon for the destination next state, just in case
// we're doing something funky and using different variables to track // we're doing something funky and using different variables to track
// the destination's past and next state (e.g. in swarm analysis). // the destination's past and next state (e.g. in swarm analysis).
private double epsilonDestNextFixed; private double suppliedKernelWidthDestNextFixed;
private double[] epsilonDestNext; private double[] suppliedKernelWidthDestNext;
private double[] epsilonDestNextInUse; private double[] kernelWidthDestNextInUse;
private double[][] destNext; private double[][] destNext;
private double[][] source; private double[][] source;
@ -56,24 +61,24 @@ public class KernelEstimatorTransferEntropyMultiVariate extends KernelEstimatorM
double epsilonDest, double epsilonSource) { double epsilonDest, double epsilonSource) {
super.initialise(destDimensionsWithPast, epsilonDest); super.initialise(destDimensionsWithPast, epsilonDest);
this.sourceDimensions = sourceDimensions; this.sourceDimensions = sourceDimensions;
this.epsilonSource = new double[sourceDimensions]; this.suppliedKernelWidthSource = new double[sourceDimensions];
for (int d = 0; d < sourceDimensions; d++) { for (int d = 0; d < sourceDimensions; d++) {
this.epsilonSource[d] = epsilonSource; this.suppliedKernelWidthSource[d] = epsilonSource;
} }
epsilonSourceInUse = new double[sourceDimensions]; kernelWidthSourceInUse = new double[sourceDimensions];
// Track that we're using a fixed epsilon for destination next // Track that we're using a fixed epsilon for destination next
epsilonDestNext = null; suppliedKernelWidthDestNext = null;
epsilonDestNextFixed = epsilonDest; suppliedKernelWidthDestNextFixed = epsilonDest;
} }
public void initialise(double[] epsilonDest, public void initialise(double[] epsilonDest,
double[] epsilonSource) { double[] epsilonSource) {
super.initialise(epsilonDest); super.initialise(epsilonDest);
this.epsilonSource = epsilonSource; this.suppliedKernelWidthSource = epsilonSource;
epsilonSourceInUse = new double[sourceDimensions]; kernelWidthSourceInUse = new double[sourceDimensions];
// Assume that we are doing an ordinary TE computation (dest past // Assume that we are doing an ordinary TE computation (dest past
// and next state are the same variable) // and next state are the same variable)
epsilonDestNext = epsilonDest; suppliedKernelWidthDestNext = epsilonDest;
} }
/** /**
@ -96,11 +101,11 @@ public class KernelEstimatorTransferEntropyMultiVariate extends KernelEstimatorM
if (normalise) { if (normalise) {
for (int d = 0; d < sourceDimensions; d++) { for (int d = 0; d < sourceDimensions; d++) {
double std = MatrixUtils.stdDev(source, d); double std = MatrixUtils.stdDev(source, d);
epsilonSourceInUse[d] = epsilonSource[d] * std; kernelWidthSourceInUse[d] = suppliedKernelWidthSource[d] * std;
} }
} else { } else {
for (int d = 0; d < sourceDimensions; d++) { for (int d = 0; d < sourceDimensions; d++) {
epsilonSourceInUse[d] = epsilonSource[d]; kernelWidthSourceInUse[d] = suppliedKernelWidthSource[d];
} }
} }
@ -109,22 +114,22 @@ public class KernelEstimatorTransferEntropyMultiVariate extends KernelEstimatorM
// we're doing something funky with different dest past and next // we're doing something funky with different dest past and next
// state variables). // state variables).
int destNextDimensions = destNext[0].length; int destNextDimensions = destNext[0].length;
if (epsilonDestNext == null) { if (suppliedKernelWidthDestNext == null) {
// We must be using a fixed epsilon // We must be using a fixed epsilon
epsilonDestNext = new double[destNextDimensions]; suppliedKernelWidthDestNext = new double[destNextDimensions];
for (int d = 0; d < destNextDimensions; d++) { for (int d = 0; d < destNextDimensions; d++) {
epsilonDestNext[d] = epsilonDestNextFixed; suppliedKernelWidthDestNext[d] = suppliedKernelWidthDestNextFixed;
} }
} }
epsilonDestNextInUse = new double[destNextDimensions]; kernelWidthDestNextInUse = new double[destNextDimensions];
if (normalise) { if (normalise) {
for (int d = 0; d < destNextDimensions; d++) { for (int d = 0; d < destNextDimensions; d++) {
double std = MatrixUtils.stdDev(destNext, d); double std = MatrixUtils.stdDev(destNext, d);
epsilonDestNextInUse[d] = epsilonDestNext[d] * std; kernelWidthDestNextInUse[d] = suppliedKernelWidthDestNext[d] * std;
} }
} else { } else {
for (int d = 0; d < destNextDimensions; d++) { for (int d = 0; d < destNextDimensions; d++) {
epsilonDestNextInUse[d] = epsilonDestNext[d]; kernelWidthDestNextInUse[d] = suppliedKernelWidthDestNext[d];
} }
} }
@ -169,7 +174,7 @@ public class KernelEstimatorTransferEntropyMultiVariate extends KernelEstimatorM
} }
public void setEpsSource(double[] epsilonSource) { public void setEpsSource(double[] epsilonSource) {
this.epsilonSource = epsilonSource; this.suppliedKernelWidthSource = epsilonSource;
} }
/** /**
@ -180,7 +185,7 @@ public class KernelEstimatorTransferEntropyMultiVariate extends KernelEstimatorM
*/ */
protected void correlatedPointAddedCallback(int correlatedTimeStep) { protected void correlatedPointAddedCallback(int correlatedTimeStep) {
boolean sourceMatches = false; boolean sourceMatches = false;
if (stepKernel(sourceObs, source[correlatedTimeStep], epsilonSourceInUse) > 0) { if (stepKernel(sourceObs, source[correlatedTimeStep], kernelWidthSourceInUse) > 0) {
countPastSource++; countPastSource++;
sourceMatches = true; sourceMatches = true;
} }
@ -191,7 +196,7 @@ public class KernelEstimatorTransferEntropyMultiVariate extends KernelEstimatorM
// is achieved simply by passing in epsilon, since // is achieved simply by passing in epsilon, since
// stepKernel just uses the first dimensions elements // stepKernel just uses the first dimensions elements
// of the widths argument). // of the widths argument).
if (stepKernel(destNextObs, destNext[correlatedTimeStep], epsilonDestNextInUse) > 0) { if (stepKernel(destNextObs, destNext[correlatedTimeStep], kernelWidthDestNextInUse) > 0) {
countNextPast++; countNextPast++;
if (sourceMatches) { if (sourceMatches) {
countNextPastSource++; countNextPastSource++;
@ -206,7 +211,7 @@ public class KernelEstimatorTransferEntropyMultiVariate extends KernelEstimatorM
*/ */
protected void correlatedPointRemovedCallback(int removedCorrelatedTimeStep) { protected void correlatedPointRemovedCallback(int removedCorrelatedTimeStep) {
boolean sourceMatches = false; boolean sourceMatches = false;
if (stepKernel(sourceObs, source[removedCorrelatedTimeStep], epsilonSourceInUse) > 0) { if (stepKernel(sourceObs, source[removedCorrelatedTimeStep], kernelWidthSourceInUse) > 0) {
countPastSource--; countPastSource--;
sourceMatches = true; sourceMatches = true;
} }
@ -217,7 +222,7 @@ public class KernelEstimatorTransferEntropyMultiVariate extends KernelEstimatorM
// is achieved simply by passing in epsilon, since // is achieved simply by passing in epsilon, since
// stepKernel just uses the first dimensions elements // stepKernel just uses the first dimensions elements
// of the widths argument). // of the widths argument).
if (stepKernel(destNextObs, destNext[removedCorrelatedTimeStep], epsilonDestNextInUse) > 0) { if (stepKernel(destNextObs, destNext[removedCorrelatedTimeStep], kernelWidthDestNextInUse) > 0) {
countNextPast--; countNextPast--;
if (sourceMatches) { if (sourceMatches) {
countNextPastSource--; countNextPastSource--;

View File

@ -143,7 +143,7 @@ public class MutualInfoCalculatorMultiVariateWithDiscreteKernel implements
double[][] obsForThisDiscValue = MatrixUtils.extractSelectedPointsMatchingCondition( double[][] obsForThisDiscValue = MatrixUtils.extractSelectedPointsMatchingCondition(
continuousObservations, discreteObservations, i, discCounts[i]); continuousObservations, discreteObservations, i, discCounts[i]);
// Set the kernel width for the relevant kernel estimator: // Set the kernel width for the relevant kernel estimator:
mvkeForEachDiscrete[i].initialise(mvke.epsilonInUse); mvkeForEachDiscrete[i].initialise(mvke.kernelWidthsInUse);
// Set these observations for the relevant kernel estimator: // Set these observations for the relevant kernel estimator:
mvkeForEachDiscrete[i].setObservations(obsForThisDiscValue); mvkeForEachDiscrete[i].setObservations(obsForThisDiscValue);
} }
@ -599,6 +599,6 @@ public class MutualInfoCalculatorMultiVariateWithDiscreteKernel implements
*/ */
public double[] getKernelWidthsInUse() { public double[] getKernelWidthsInUse() {
// Return a copy so that the user can't mess with it // Return a copy so that the user can't mess with it
return Arrays.copyOf(mvke.epsilonInUse, mvke.epsilonInUse.length); return Arrays.copyOf(mvke.kernelWidthsInUse, mvke.kernelWidthsInUse.length);
} }
} }