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 Vector[] observations = null; - bins = (int) Math.ceil((max - min) / epsilonInUse); + bins = (int) Math.ceil((max - min) / kernelWidthInUse); if (bins == 0) { // The max and min are the same. // 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. int topIndex; 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--) { // This observation is within epsilon. // Before adding to the count just check if it's a dynamic correlation if required: @@ -233,7 +239,7 @@ public class KernelEstimatorSingleVariate { int bottomIndex; for (bottomIndex = 0; (bottomIndex < sortedObservations[bin+1].length) && - (sortedObservations[bin+1][bottomIndex].observation < observation + epsilonInUse); + (sortedObservations[bin+1][bottomIndex].observation < observation + kernelWidthInUse); bottomIndex++) { // This observation is within epsilon. // 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) { - 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: if (bin >= bins) { bin = bins - 1; diff --git a/java/source/infodynamics/measures/continuous/kernel/KernelEstimatorTransferEntropy.java b/java/source/infodynamics/measures/continuous/kernel/KernelEstimatorTransferEntropy.java index be2448a..6d37594 100755 --- a/java/source/infodynamics/measures/continuous/kernel/KernelEstimatorTransferEntropy.java +++ b/java/source/infodynamics/measures/continuous/kernel/KernelEstimatorTransferEntropy.java @@ -13,13 +13,16 @@ import infodynamics.utils.MatrixUtils; * function on the joint history. *

* - * @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,
joseph.lizier at gmail.com * */ public class KernelEstimatorTransferEntropy extends KernelEstimatorMultiVariate { - private double epsilonSource; - private double epsilonSourceInUse; + private double suppliedKernelWidthSource; + private double kernelWidthSourceInUse; private double[] destNext; private double[] source; @@ -42,13 +45,13 @@ public class KernelEstimatorTransferEntropy extends KernelEstimatorMultiVariate public void initialise(int dimensions, double epsilon) { super.initialise(dimensions, epsilon); - this.epsilonSource = epsilon; + this.suppliedKernelWidthSource = epsilon; } public void initialise(int dimensions, double epsilonDest, double epsilonSource) { super.initialise(dimensions, epsilonDest); - this.epsilonSource = epsilonSource; + this.suppliedKernelWidthSource = epsilonSource; } public void setObservations(double[][] destPastVectors, @@ -61,9 +64,9 @@ public class KernelEstimatorTransferEntropy extends KernelEstimatorMultiVariate if (normalise) { double std = MatrixUtils.stdDev(source); - epsilonSourceInUse = epsilonSource * std; + kernelWidthSourceInUse = suppliedKernelWidthSource * std; } else { - epsilonSourceInUse = epsilonSource; + kernelWidthSourceInUse = suppliedKernelWidthSource; } this.source = source; @@ -107,7 +110,7 @@ public class KernelEstimatorTransferEntropy extends KernelEstimatorMultiVariate } 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) { boolean sourceMatches = false; - if (Math.abs(sourceObs - source[correlatedTimeStep]) <= epsilonSourceInUse) { + if (Math.abs(sourceObs - source[correlatedTimeStep]) <= kernelWidthSourceInUse) { countPastSource++; sourceMatches = true; } // The epsilons across the destination variables should all be approximately // equal, so just use the first one. - if (Math.abs(destNextObs - destNext[correlatedTimeStep]) <= epsilonInUse[0]) { + if (Math.abs(destNextObs - destNext[correlatedTimeStep]) <= kernelWidthsInUse[0]) { countNextPast++; if (sourceMatches) { countNextPastSource++; @@ -139,13 +142,13 @@ public class KernelEstimatorTransferEntropy extends KernelEstimatorMultiVariate */ protected void correlatedPointRemovedCallback(int removedCorrelatedTimeStep) { boolean sourceMatches = false; - if (Math.abs(sourceObs - source[removedCorrelatedTimeStep]) <= epsilonSourceInUse) { + if (Math.abs(sourceObs - source[removedCorrelatedTimeStep]) <= kernelWidthSourceInUse) { countPastSource--; sourceMatches = true; } // The epsilons across the destination variables should all be approximately // equal, so just use the first one. - if (Math.abs(destNextObs - destNext[removedCorrelatedTimeStep]) <= epsilonInUse[0]) { + if (Math.abs(destNextObs - destNext[removedCorrelatedTimeStep]) <= kernelWidthsInUse[0]) { countNextPast--; if (sourceMatches) { countNextPastSource--; diff --git a/java/source/infodynamics/measures/continuous/kernel/KernelEstimatorTransferEntropyMultiVariate.java b/java/source/infodynamics/measures/continuous/kernel/KernelEstimatorTransferEntropyMultiVariate.java index 52e2a56..cc96bd3 100755 --- a/java/source/infodynamics/measures/continuous/kernel/KernelEstimatorTransferEntropyMultiVariate.java +++ b/java/source/infodynamics/measures/continuous/kernel/KernelEstimatorTransferEntropyMultiVariate.java @@ -6,28 +6,33 @@ package infodynamics.measures.continuous.kernel; import infodynamics.utils.MatrixUtils; /** - *

Kernel 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); } }