From b02760ddd37f086a8fb07c996a2c465ee12c0ebc Mon Sep 17 00:00:00 2001 From: Joseph Lizier Date: Mon, 15 Nov 2021 10:58:59 +1100 Subject: [PATCH] Adding overloads on setObservations and addObservations for MI and TE calculators to handle one variable univariate and one variable multivariate --- .../ChannelCalculatorMultiVariate.java | 94 +++++++++++++++++++ .../MutualInfoMultiVariateCommon.java | 40 ++++++++ ...lculatorMultiVariateViaCondMutualInfo.java | 52 ++++++++++ ...erEntropyCalculatorMultiVariateKernel.java | 50 ++++++++++ 4 files changed, 236 insertions(+) diff --git a/java/source/infodynamics/measures/continuous/ChannelCalculatorMultiVariate.java b/java/source/infodynamics/measures/continuous/ChannelCalculatorMultiVariate.java index 4f5c198..684a0f9 100755 --- a/java/source/infodynamics/measures/continuous/ChannelCalculatorMultiVariate.java +++ b/java/source/infodynamics/measures/continuous/ChannelCalculatorMultiVariate.java @@ -73,6 +73,46 @@ public interface ChannelCalculatorMultiVariate extends ChannelCalculatorCommon { */ public void setObservations(double[][] source, double[][] destination) throws Exception; + /** + * Sets a single series from which to compute the PDF for the channel measure -- + * available ONLY if sourceDimensions was initialised + * to 1. + * Cannot be called in conjunction with other methods for setting/adding + * observations. + * + *

The supplied series are certainly (multivariate) time-series for time-series measures + * such as transfer entropy, however may be simply a set of separate observations + * for the mutual information without a time interpretation. + * + * @param source series of univariate observations for the source variable + * (first index is time or observation index, second is variable number) + * @param destination series of multivariate observations for the destination variable + * (first index is time or observation index, second is variable number). + * Length must match source, and their indices must correspond. + * @throws Exception + */ + public void setObservations(double[] source, double[][] destination) throws Exception; + + /** + * Sets a single series from which to compute the PDF for the channel measure -- + * available ONLY if destDimensions was initialised + * to 1. + * Cannot be called in conjunction with other methods for setting/adding + * observations. + * + *

The supplied series are certainly (multivariate) time-series for time-series measures + * such as transfer entropy, however may be simply a set of separate observations + * for the mutual information without a time interpretation. + * + * @param source series of multivariate observations for the source variable + * (first index is time or observation index, second is variable number) + * @param destination series of univariate observations for the destination variable + * (first index is time or observation index, second is variable number). + * Length must match source, and their indices must correspond. + * @throws Exception + */ + public void setObservations(double[][] source, double[] destination) throws Exception; + /** * Sets a single pair of univariate series from which to compute the PDF for the channel measure -- * available ONLY if both sourceDimensions and destDimensions were initialised @@ -126,6 +166,60 @@ public interface ChannelCalculatorMultiVariate extends ChannelCalculatorCommon { */ public void addObservations(double[][] source, double[][] destination) throws Exception; + /** + *

Adds a new set of observations to update the PDFs with - is + * intended to be called multiple times. + * Available ONLY if sourceDimensions was initialised to 1. + * Must be called after {@link #startAddObservations()}; call + * {@link #finaliseAddObservations()} once all observations have + * been supplied.

+ * + *

Important: this does not append these observations to the previously + * supplied observations, but treats them independently - i.e. measurements + * such as the transfer entropy will not join them up to examine k + * consecutive values in time.

+ * + *

Note that the arrays source and destination must not be over-written by the user + * until after finaliseAddObservations() has been called + * (they are not copied by this method necessarily, but the method + * may simply hold a pointer to them).

+ * + * @param source series of uniivariate observations for the source variable + * (first index is time or observation index, second is variable number) + * @param destination series of multivariate observations for the destination variable + * (first index is time or observation index, second is variable number). + * Length must match source, and their indices must correspond. + * @throws Exception + */ + public void addObservations(double[] source, double[][] destination) throws Exception; + + /** + *

Adds a new set of observations to update the PDFs with - is + * intended to be called multiple times. + * Available ONLY if destDimensions was initialised to 1. + * Must be called after {@link #startAddObservations()}; call + * {@link #finaliseAddObservations()} once all observations have + * been supplied.

+ * + *

Important: this does not append these observations to the previously + * supplied observations, but treats them independently - i.e. measurements + * such as the transfer entropy will not join them up to examine k + * consecutive values in time.

+ * + *

Note that the arrays source and destination must not be over-written by the user + * until after finaliseAddObservations() has been called + * (they are not copied by this method necessarily, but the method + * may simply hold a pointer to them).

+ * + * @param source series of multivariate observations for the source variable + * (first index is time or observation index, second is variable number) + * @param destination series of uniivariate observations for the destination variable + * (first index is time or observation index, second is variable number). + * Length must match source, and their indices must correspond. + * @throws Exception + */ + public void addObservations(double[][] source, double[] destination) throws Exception; + /** *

Adds a new set of univariate observations to update the PDFs with. * available ONLY if both sourceDimensions and destDimensions were initialised diff --git a/java/source/infodynamics/measures/continuous/MutualInfoMultiVariateCommon.java b/java/source/infodynamics/measures/continuous/MutualInfoMultiVariateCommon.java index f97c66f..ec45d02 100755 --- a/java/source/infodynamics/measures/continuous/MutualInfoMultiVariateCommon.java +++ b/java/source/infodynamics/measures/continuous/MutualInfoMultiVariateCommon.java @@ -282,6 +282,20 @@ public abstract class MutualInfoMultiVariateCommon implements setObservations(source, destination); } + @Override + public void setObservations(double[] source, double[][] destination) throws Exception { + startAddObservations(); + addObservations(source, destination); + finaliseAddObservations(); + } + + @Override + public void setObservations(double[][] source, double[] destination) throws Exception { + startAddObservations(); + addObservations(source, destination); + finaliseAddObservations(); + } + @Override public void startAddObservations() { vectorOfSourceObservations = new Vector(); @@ -351,6 +365,32 @@ public abstract class MutualInfoMultiVariateCommon implements addObservations(source, destination); } + @Override + public void addObservations(double[] source, double[][] destination) throws Exception { + + if (dimensionsSource != 1) { + throw new Exception("The number of source dimensions (having been initialised to " + + dimensionsSource + ") can only be 1 when " + + "the partially univariate addObservations(double[],double[][]) and " + + "setObservations(double[],double[][]) methods are called"); + } + addObservations(MatrixUtils.reshape(source, source.length, 1), + destination); + } + + @Override + public void addObservations(double[][] source, double[] destination) throws Exception { + + if (dimensionsDest != 1) { + throw new Exception("The number of dest dimensions (having been initialised to " + + dimensionsDest + ") can only be 1 when " + + "the partially univariate addObservations(double[][],double[]) and " + + "setObservations(double[][],double[]) methods are called"); + } + addObservations(source, + MatrixUtils.reshape(destination, destination.length, 1)); + } + public void addObservations(double[][] source, double[][] destination, int startTime, int numTimeSteps) throws Exception { if (vectorOfSourceObservations == null) { diff --git a/java/source/infodynamics/measures/continuous/TransferEntropyCalculatorMultiVariateViaCondMutualInfo.java b/java/source/infodynamics/measures/continuous/TransferEntropyCalculatorMultiVariateViaCondMutualInfo.java index b9955da..62f7011 100755 --- a/java/source/infodynamics/measures/continuous/TransferEntropyCalculatorMultiVariateViaCondMutualInfo.java +++ b/java/source/infodynamics/measures/continuous/TransferEntropyCalculatorMultiVariateViaCondMutualInfo.java @@ -257,6 +257,30 @@ public class TransferEntropyCalculatorMultiVariateViaCondMutualInfo super.setObservations(source, destination); } + @Override + public void setObservations(double[] source, double[][] destination) + throws Exception { + if (sourceDimensions != 1) { + throw new Exception("Cannot call the partially univariate addObservations if you " + + "have initialised with dimension > 1 for source"); + } + startAddObservations(); + addObservations(source, destination); + finaliseAddObservations(); + } + + @Override + public void setObservations(double[][] source, double[] destination) + throws Exception { + if (destDimensions != 1) { + throw new Exception("Cannot call the partially univariate addObservations if you " + + "have initialised with dimension > 1 for dest"); + } + startAddObservations(); + addObservations(source, destination); + finaliseAddObservations(); + } + @Override public void startAddObservations() { if ((sourceDimensions == 1) && (destDimensions == 1)) { @@ -293,6 +317,34 @@ public class TransferEntropyCalculatorMultiVariateViaCondMutualInfo super.addObservations(source, destination); } + /* (non-Javadoc) + * @see infodynamics.measures.continuous.ChannelCalculatorMultiVariate#addObservations(double[], double[][]) + */ + @Override + public void addObservations(double[] source, double[][] destination) throws Exception { + + if (sourceDimensions != 1) { + throw new Exception("Cannot call the partially univariate addObservations if you " + + "have initialised with dimension > 1 for source"); + } + addObservations(MatrixUtils.reshape(source, source.length, 1), + destination); + } + + /* (non-Javadoc) + * @see infodynamics.measures.continuous.ChannelCalculatorMultiVariate#addObservations(double[][], double[]) + */ + @Override + public void addObservations(double[][] source, double[] destination) throws Exception { + + if (destDimensions != 1) { + throw new Exception("Cannot call the partially univariate addObservations if you " + + "have initialised with dimension > 1 for dest"); + } + addObservations(source, + MatrixUtils.reshape(destination, destination.length, 1)); + } + /* (non-Javadoc) * @see infodynamics.measures.continuous.ChannelCalculatorMultiVariate#addObservations(double[][], double[][]) */ diff --git a/java/source/infodynamics/measures/continuous/kernel/TransferEntropyCalculatorMultiVariateKernel.java b/java/source/infodynamics/measures/continuous/kernel/TransferEntropyCalculatorMultiVariateKernel.java index 3cdc9c7..aa28aa3 100755 --- a/java/source/infodynamics/measures/continuous/kernel/TransferEntropyCalculatorMultiVariateKernel.java +++ b/java/source/infodynamics/measures/continuous/kernel/TransferEntropyCalculatorMultiVariateKernel.java @@ -274,6 +274,30 @@ public class TransferEntropyCalculatorMultiVariateKernel finaliseAddObservations(); } + @Override + public void setObservations(double[] source, double[][] destination) + throws Exception { + if (sourceDimensions != 1) { + throw new Exception("Cannot call the partially univariate addObservations if you " + + "have initialised with dimension > 1 for source"); + } + startAddObservations(); + addObservations(source, destination); + finaliseAddObservations(); + } + + @Override + public void setObservations(double[][] source, double[] destination) + throws Exception { + if (destDimensions != 1) { + throw new Exception("Cannot call the partially univariate addObservations if you " + + "have initialised with dimension > 1 for dest"); + } + startAddObservations(); + addObservations(source, destination); + finaliseAddObservations(); + } + @Override public void setObservations(double[][] source, double[][] destination, boolean[] sourceValid, boolean[] destValid) throws Exception { @@ -358,6 +382,32 @@ public class TransferEntropyCalculatorMultiVariateKernel vectorOfJointSourceObservations.add(source); vectorOfJointDestinationObservations.add(destination); } + + @Override + public void addObservations(double[] source, double[][] destination) throws Exception { + + if (sourceDimensions != 1) { + throw new Exception("The number of source dimensions (having been initialised to " + + sourceDimensions + ") can only be 1 when " + + "the partially univariate addObservations(double[],double[][]) and " + + "setObservations(double[],double[][]) methods are called"); + } + addObservations(MatrixUtils.reshape(source, source.length, 1), + destination); + } + + @Override + public void addObservations(double[][] source, double[] destination) throws Exception { + + if (destDimensions != 1) { + throw new Exception("The number of dest dimensions (having been initialised to " + + destDimensions + ") can only be 1 when " + + "the partially univariate addObservations(double[][],double[]) and " + + "setObservations(double[][],double[]) methods are called"); + } + addObservations(source, + MatrixUtils.reshape(destination, destination.length, 1)); + } @Override public void addObservations(double[][] source, double[][] destination,