From 5bde6f295b8bb18db89526d3b77fc12a7f9e95a8 Mon Sep 17 00:00:00 2001 From: jlizier Date: Tue, 19 Jun 2018 23:08:13 +1000 Subject: [PATCH] Fixes issue #70 by providing setObservations(double[], int[], double[]) methods for the mixed CMI calculators (i.e. allowing univariate arrays to be passed in if dimension 1 was defined for both the continuous data and conditional). Unit test validating is included. --- ...culatorMultiVariateWithDiscreteSource.java | 24 ++++++ ...rMultiVariateWithDiscreteSourceCommon.java | 21 +++++ ...alMutualInfoWithDiscreteKraskovTester.java | 77 +++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 java/unittests/infodynamics/measures/mixed/kraskov/ConditionalMutualInfoWithDiscreteKraskovTester.java diff --git a/java/source/infodynamics/measures/mixed/ConditionalMutualInfoCalculatorMultiVariateWithDiscreteSource.java b/java/source/infodynamics/measures/mixed/ConditionalMutualInfoCalculatorMultiVariateWithDiscreteSource.java index 579a35a..c9e6097 100755 --- a/java/source/infodynamics/measures/mixed/ConditionalMutualInfoCalculatorMultiVariateWithDiscreteSource.java +++ b/java/source/infodynamics/measures/mixed/ConditionalMutualInfoCalculatorMultiVariateWithDiscreteSource.java @@ -55,9 +55,33 @@ public interface ConditionalMutualInfoCalculatorMultiVariateWithDiscreteSource { public void addObservations(double[][] continuousObservations, int[] discreteObservations, double[][] conditionedObservations) throws Exception; + /** + * Method to add observations. Can only be called when the continuous observations and + * the conditionals were both set to have dimension 1 in {@link #initialise(int, int, int)} + * + * @param continuousObservations + * @param discreteObservations + * @param conditionedObservations + * @throws Exception + */ + public void addObservations(double[] continuousObservations, + int[] discreteObservations, double[] conditionedObservations) throws Exception; + public void setObservations(double[][] continuousObservations, int[] discreteObservations, double[][] conditionedObservations) throws Exception; + /** + * Method to set observations. Can only be called when the continuous observations and + * the conditionals were both set to have dimension 1 in {@link #initialise(int, int, int)} + * + * @param continuousObservations + * @param discreteObservations + * @param conditionedObservations + * @throws Exception + */ + public void setObservations(double[] continuousObservations, + int[] discreteObservations, double[] conditionedObservations) throws Exception; + public double computeAverageLocalOfObservations() throws Exception; public double[] computeLocalOfPreviousObservations() throws Exception; diff --git a/java/source/infodynamics/measures/mixed/ConditionalMutualInfoCalculatorMultiVariateWithDiscreteSourceCommon.java b/java/source/infodynamics/measures/mixed/ConditionalMutualInfoCalculatorMultiVariateWithDiscreteSourceCommon.java index 8e249c4..294dd80 100755 --- a/java/source/infodynamics/measures/mixed/ConditionalMutualInfoCalculatorMultiVariateWithDiscreteSourceCommon.java +++ b/java/source/infodynamics/measures/mixed/ConditionalMutualInfoCalculatorMultiVariateWithDiscreteSourceCommon.java @@ -131,6 +131,13 @@ public abstract class ConditionalMutualInfoCalculatorMultiVariateWithDiscreteSou throw new RuntimeException("Not implemented yet"); } + @Override + public void addObservations(double[] continuousObservations, + int[] discreteObservations, double[] conditionedObservations) + throws Exception { + throw new RuntimeException("Not implemented yet"); + } + public void setObservations(double[][] continuousObservations, int[] discreteObservations, double[][] conditionedObservations) throws Exception { @@ -156,6 +163,20 @@ public abstract class ConditionalMutualInfoCalculatorMultiVariateWithDiscreteSou } + @Override + public void setObservations(double[] continuousObservations, + int[] discreteObservations, double[] conditionedObservations) + throws Exception { + if ((dimensionsContinuous != 1) || (dimensionsConditional != 1)) { + throw new Exception("setObservations(double[], int[], double[]) can only be called when both the continuous observations and conditional observations were initialised to have dimension 1"); + } + double[][] contObservationsMatrix = new double[continuousObservations.length][1]; + MatrixUtils.copyIntoColumn(contObservationsMatrix, 0, continuousObservations); + double[][] condObservationsMatrix = new double[conditionedObservations.length][1]; + MatrixUtils.copyIntoColumn(condObservationsMatrix, 0, conditionedObservations); + setObservations(contObservationsMatrix, discreteObservations, condObservationsMatrix); + } + /** * Compute the significance of the mutual information of the previously supplied observations. * We destroy the p(x,d|z) correlations, while retaining the p(x|z) marginals, to check how diff --git a/java/unittests/infodynamics/measures/mixed/kraskov/ConditionalMutualInfoWithDiscreteKraskovTester.java b/java/unittests/infodynamics/measures/mixed/kraskov/ConditionalMutualInfoWithDiscreteKraskovTester.java new file mode 100644 index 0000000..6bf8b5d --- /dev/null +++ b/java/unittests/infodynamics/measures/mixed/kraskov/ConditionalMutualInfoWithDiscreteKraskovTester.java @@ -0,0 +1,77 @@ +package infodynamics.measures.mixed.kraskov; + +import infodynamics.utils.RandomGenerator; +import junit.framework.TestCase; + +public class ConditionalMutualInfoWithDiscreteKraskovTester extends TestCase { + + public void testUnivariateArrayMethods() { + ConditionalMutualInfoCalculatorMultiVariateWithDiscreteKraskov cmiCalc = + new ConditionalMutualInfoCalculatorMultiVariateWithDiscreteKraskov(); + boolean exceptionCaught = false; + int dataLength = 1000; + RandomGenerator rg = new RandomGenerator(); + double[] univariateContData1 = rg.generateNormalData(dataLength, 0, 1); + double[][] multivariateActualUniContData1 = rg.generateNormalData(dataLength, 1, 0, 1); + double[][] multivariateContData1 = rg.generateNormalData(dataLength, 2, 0, 1); + int[] discData = rg.generateRandomInts(dataLength, 2); + double[] univariateCondData = rg.generateNormalData(dataLength, 0, 1); + double[][] multivariateActualUniCondData = rg.generateNormalData(dataLength, 1, 0, 1); + double[][] multivariateCondData = rg.generateNormalData(dataLength, 2, 0, 1); + + // Testing when univariate methods should work + cmiCalc.initialise(1, 2, 1); + try { + cmiCalc.setObservations(univariateContData1, discData, univariateCondData); + cmiCalc.initialise(1, 2, 1); + cmiCalc.setObservations(multivariateActualUniContData1, discData, multivariateActualUniCondData); + } catch (Exception e) { + exceptionCaught = true; + } + assertFalse(exceptionCaught); + // and now supply actual multivariates here which is wrong: + cmiCalc.initialise(1, 2, 1); + try{ + cmiCalc.setObservations(multivariateContData1, discData, multivariateCondData); + } catch (Exception e) { + exceptionCaught = true; + } + assertTrue(exceptionCaught); + exceptionCaught = false; + + // Testing when univariate methods should not work + cmiCalc.initialise(2, 2, 1); + try { + cmiCalc.setObservations(univariateContData1, discData, univariateCondData); + } catch (Exception e) { + exceptionCaught = true; + } + assertTrue(exceptionCaught); + exceptionCaught = false; + cmiCalc.initialise(1, 2, 2); + try { + cmiCalc.setObservations(univariateContData1, discData, univariateCondData); + } catch (Exception e) { + exceptionCaught = true; + } + assertTrue(exceptionCaught); + exceptionCaught = false; + cmiCalc.initialise(2, 2, 2); + try { + cmiCalc.setObservations(univariateContData1, discData, univariateCondData); + } catch (Exception e) { + exceptionCaught = true; + } + assertTrue(exceptionCaught); + exceptionCaught = false; + // and now supply the proper multivariate arrays: + cmiCalc.initialise(2, 2, 2); + try { + cmiCalc.setObservations(multivariateContData1, discData, multivariateCondData); + } catch (Exception e) { + exceptionCaught = true; + } + assertFalse(exceptionCaught); + } + +}