diff --git a/java/source/infodynamics/measures/continuous/kernel/KernelEstimatorMultiVariate.java b/java/source/infodynamics/measures/continuous/kernel/KernelEstimatorMultiVariate.java index 28e30d4..5f6df7a 100755 --- a/java/source/infodynamics/measures/continuous/kernel/KernelEstimatorMultiVariate.java +++ b/java/source/infodynamics/measures/continuous/kernel/KernelEstimatorMultiVariate.java @@ -8,17 +8,24 @@ import java.util.Hashtable; /** - * Class to maintain probability distribution function for - * a single variable, using kernel estimates. + *
Class to maintain probability distribution function for + * a multivariate set, using kernel estimates.
* + *+ * For more details on kernel estimation for computing probability distribution functions, + * see Kantz and Schreiber (below). + *
* - * @author Joseph Lizier + * @see KernelEstimatorSingleVariate + * @see "H. Kantz and T. Schreiber, 'Nonlinear Time Series Analysis'. + * Cambridge, MA: Cambridge University Press, 1997" + * @author Joseph Lizier, joseph.lizier at gmail.com> * */ public class KernelEstimatorMultiVariate implements Cloneable { - protected double[] epsilon = null; - protected double[] epsilonInUse = null; + protected double[] suppliedKernelWidths = null; + protected double[] kernelWidthsInUse = null; protected int dimensions = 1; private int[] bins = null; private boolean usingIntegerIndexBins = true; @@ -107,9 +114,9 @@ public class KernelEstimatorMultiVariate implements Cloneable { */ public void initialise(int dimensions, double epsilon) { this.dimensions = dimensions; - this.epsilon = new double[dimensions]; + this.suppliedKernelWidths = new double[dimensions]; for (int d = 0; d < dimensions; d++) { - this.epsilon[d] = epsilon; + this.suppliedKernelWidths[d] = epsilon; } finishInitialisation(); } @@ -121,9 +128,9 @@ public class KernelEstimatorMultiVariate implements Cloneable { */ public void initialise(double[] epsilon) { dimensions = epsilon.length; - this.epsilon = new double[dimensions]; + this.suppliedKernelWidths = new double[dimensions]; for (int d = 0; d < dimensions; d++) { - this.epsilon[d] = epsilon[d]; + this.suppliedKernelWidths[d] = epsilon[d]; } finishInitialisation(); } @@ -142,7 +149,7 @@ public class KernelEstimatorMultiVariate implements Cloneable { multipliers = null; rawData = null; 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. // This saves us from normalising all of the incoming data points! std = MatrixUtils.stdDev(data, d); - epsilonInUse[d] = epsilon[d] * std; + kernelWidthsInUse[d] = suppliedKernelWidths[d] * std; } 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) { // This means the min and max are exactly the same: // 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] + ", bins: " + bins[d] + (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) { - 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: if (bin >= bins[dimension]) { bin = bins[dimension] - 1; @@ -915,7 +922,7 @@ public class KernelEstimatorMultiVariate implements Cloneable { */ public int stepKernel(double[] observation, double[] candidate) { 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; } } diff --git a/java/source/infodynamics/measures/continuous/kernel/KernelEstimatorSingleVariate.java b/java/source/infodynamics/measures/continuous/kernel/KernelEstimatorSingleVariate.java index 2c86530..ce451f9 100755 --- a/java/source/infodynamics/measures/continuous/kernel/KernelEstimatorSingleVariate.java +++ b/java/source/infodynamics/measures/continuous/kernel/KernelEstimatorSingleVariate.java @@ -6,17 +6,23 @@ import java.util.Vector; import java.util.Arrays; /** - * Class to maintain probability distribution function for - * a single variable, using kernel estimates. + *Class to maintain probability distribution function for + * a single variable, using kernel estimates.
* + *+ * For more details on kernel estimation for computing probability distribution functions, + * see Kantz and Schreiber (below). + *
* - * @author Joseph Lizier + * @see "H. Kantz and T. Schreiber, 'Nonlinear Time Series Analysis'. + * Cambridge, MA: Cambridge University Press, 1997" + * @author Joseph Lizier, joseph.lizier at gmail.com> * */ public class KernelEstimatorSingleVariate { - private double epsilon = 0.1; - private double epsilonInUse; + private double suppliedKernelWidth = 0.1; + private double kernelWidthInUse; private double min = 0; private double max = 0; private int bins = 0; @@ -72,7 +78,7 @@ public class KernelEstimatorSingleVariate { * @param epsilon */ public void initialise(double epsilon) { - this.epsilon = epsilon; + this.suppliedKernelWidth = epsilon; sortedObservations = null; } @@ -90,14 +96,14 @@ public class KernelEstimatorSingleVariate { // it should expand with the standard deviation. // This saves us from normalising all of the incoming data points! double std = MatrixUtils.stdDev(data); - epsilonInUse = epsilon * std; + kernelWidthInUse = suppliedKernelWidth * std; } else { - epsilonInUse = epsilon; + kernelWidthInUse = suppliedKernelWidth; } // Create the bins VectorKernel estimator for use with the transfer entropy.
+ *Kernel estimator for use with the transfer entropy on + * multivariate source and destination.
* *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 * function on the joint history. *
* - * @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, joseph.lizier at gmail.com> * */ public class KernelEstimatorTransferEntropyMultiVariate extends KernelEstimatorMultiVariate { private int sourceDimensions; - private double[] epsilonSource; - private double[] epsilonSourceInUse; + private double[] suppliedKernelWidthSource; + private double[] kernelWidthSourceInUse; // Keep a separate epsilon for the destination next state, just in case // we're doing something funky and using different variables to track // the destination's past and next state (e.g. in swarm analysis). - private double epsilonDestNextFixed; - private double[] epsilonDestNext; - private double[] epsilonDestNextInUse; + private double suppliedKernelWidthDestNextFixed; + private double[] suppliedKernelWidthDestNext; + private double[] kernelWidthDestNextInUse; private double[][] destNext; private double[][] source; @@ -56,24 +61,24 @@ public class KernelEstimatorTransferEntropyMultiVariate extends KernelEstimatorM double epsilonDest, double epsilonSource) { super.initialise(destDimensionsWithPast, epsilonDest); this.sourceDimensions = sourceDimensions; - this.epsilonSource = new double[sourceDimensions]; + this.suppliedKernelWidthSource = new double[sourceDimensions]; 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 - epsilonDestNext = null; - epsilonDestNextFixed = epsilonDest; + suppliedKernelWidthDestNext = null; + suppliedKernelWidthDestNextFixed = epsilonDest; } public void initialise(double[] epsilonDest, double[] epsilonSource) { super.initialise(epsilonDest); - this.epsilonSource = epsilonSource; - epsilonSourceInUse = new double[sourceDimensions]; + this.suppliedKernelWidthSource = epsilonSource; + kernelWidthSourceInUse = new double[sourceDimensions]; // Assume that we are doing an ordinary TE computation (dest past // and next state are the same variable) - epsilonDestNext = epsilonDest; + suppliedKernelWidthDestNext = epsilonDest; } /** @@ -96,11 +101,11 @@ public class KernelEstimatorTransferEntropyMultiVariate extends KernelEstimatorM if (normalise) { for (int d = 0; d < sourceDimensions; d++) { double std = MatrixUtils.stdDev(source, d); - epsilonSourceInUse[d] = epsilonSource[d] * std; + kernelWidthSourceInUse[d] = suppliedKernelWidthSource[d] * std; } } else { 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 // state variables). int destNextDimensions = destNext[0].length; - if (epsilonDestNext == null) { + if (suppliedKernelWidthDestNext == null) { // We must be using a fixed epsilon - epsilonDestNext = new double[destNextDimensions]; + suppliedKernelWidthDestNext = new double[destNextDimensions]; for (int d = 0; d < destNextDimensions; d++) { - epsilonDestNext[d] = epsilonDestNextFixed; + suppliedKernelWidthDestNext[d] = suppliedKernelWidthDestNextFixed; } } - epsilonDestNextInUse = new double[destNextDimensions]; + kernelWidthDestNextInUse = new double[destNextDimensions]; if (normalise) { for (int d = 0; d < destNextDimensions; d++) { double std = MatrixUtils.stdDev(destNext, d); - epsilonDestNextInUse[d] = epsilonDestNext[d] * std; + kernelWidthDestNextInUse[d] = suppliedKernelWidthDestNext[d] * std; } } else { 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) { - this.epsilonSource = epsilonSource; + this.suppliedKernelWidthSource = epsilonSource; } /** @@ -180,7 +185,7 @@ public class KernelEstimatorTransferEntropyMultiVariate extends KernelEstimatorM */ protected void correlatedPointAddedCallback(int correlatedTimeStep) { boolean sourceMatches = false; - if (stepKernel(sourceObs, source[correlatedTimeStep], epsilonSourceInUse) > 0) { + if (stepKernel(sourceObs, source[correlatedTimeStep], kernelWidthSourceInUse) > 0) { countPastSource++; sourceMatches = true; } @@ -191,7 +196,7 @@ public class KernelEstimatorTransferEntropyMultiVariate extends KernelEstimatorM // is achieved simply by passing in epsilon, since // stepKernel just uses the first dimensions elements // of the widths argument). - if (stepKernel(destNextObs, destNext[correlatedTimeStep], epsilonDestNextInUse) > 0) { + if (stepKernel(destNextObs, destNext[correlatedTimeStep], kernelWidthDestNextInUse) > 0) { countNextPast++; if (sourceMatches) { countNextPastSource++; @@ -206,7 +211,7 @@ public class KernelEstimatorTransferEntropyMultiVariate extends KernelEstimatorM */ protected void correlatedPointRemovedCallback(int removedCorrelatedTimeStep) { boolean sourceMatches = false; - if (stepKernel(sourceObs, source[removedCorrelatedTimeStep], epsilonSourceInUse) > 0) { + if (stepKernel(sourceObs, source[removedCorrelatedTimeStep], kernelWidthSourceInUse) > 0) { countPastSource--; sourceMatches = true; } @@ -217,7 +222,7 @@ public class KernelEstimatorTransferEntropyMultiVariate extends KernelEstimatorM // is achieved simply by passing in epsilon, since // stepKernel just uses the first dimensions elements // of the widths argument). - if (stepKernel(destNextObs, destNext[removedCorrelatedTimeStep], epsilonDestNextInUse) > 0) { + if (stepKernel(destNextObs, destNext[removedCorrelatedTimeStep], kernelWidthDestNextInUse) > 0) { countNextPast--; if (sourceMatches) { countNextPastSource--; diff --git a/java/source/infodynamics/measures/continuous/kernel/MutualInfoCalculatorMultiVariateWithDiscreteKernel.java b/java/source/infodynamics/measures/continuous/kernel/MutualInfoCalculatorMultiVariateWithDiscreteKernel.java index bbbca01..73646c2 100755 --- a/java/source/infodynamics/measures/continuous/kernel/MutualInfoCalculatorMultiVariateWithDiscreteKernel.java +++ b/java/source/infodynamics/measures/continuous/kernel/MutualInfoCalculatorMultiVariateWithDiscreteKernel.java @@ -143,7 +143,7 @@ public class MutualInfoCalculatorMultiVariateWithDiscreteKernel implements double[][] obsForThisDiscValue = MatrixUtils.extractSelectedPointsMatchingCondition( continuousObservations, discreteObservations, i, discCounts[i]); // 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: mvkeForEachDiscrete[i].setObservations(obsForThisDiscValue); } @@ -599,6 +599,6 @@ public class MutualInfoCalculatorMultiVariateWithDiscreteKernel implements */ public double[] getKernelWidthsInUse() { // 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); } }