From f67e2748192bb557f2da4a7bdafa46b31946fdff Mon Sep 17 00:00:00 2001
From: Pedro Mediano
Date: Sun, 24 Jan 2021 22:06:39 +0000
Subject: [PATCH] Added Gaussian implementation of various multivariate IT
measures and unit tests.
---
...ualTotalCorrelationCalculatorGaussian.java | 122 ++++++++++++++
...iVariateInfoMeasureCalculatorGaussian.java | 152 ++++++++++++++++++
.../gaussian/OInfoCalculatorGaussian.java | 134 +++++++++++++++
.../gaussian/SInfoCalculatorGaussian.java | 120 ++++++++++++++
...alCorrelationCalculatorGaussianTester.java | 133 +++++++++++++++
.../OInfoCalculatorGaussianTester.java | 150 +++++++++++++++++
.../SInfoCalculatorGaussianTester.java | 129 +++++++++++++++
7 files changed, 940 insertions(+)
create mode 100644 java/source/infodynamics/measures/continuous/gaussian/DualTotalCorrelationCalculatorGaussian.java
create mode 100644 java/source/infodynamics/measures/continuous/gaussian/MultiVariateInfoMeasureCalculatorGaussian.java
create mode 100644 java/source/infodynamics/measures/continuous/gaussian/OInfoCalculatorGaussian.java
create mode 100644 java/source/infodynamics/measures/continuous/gaussian/SInfoCalculatorGaussian.java
create mode 100644 java/unittests/infodynamics/measures/continuous/gaussian/DualTotalCorrelationCalculatorGaussianTester.java
create mode 100644 java/unittests/infodynamics/measures/continuous/gaussian/OInfoCalculatorGaussianTester.java
create mode 100644 java/unittests/infodynamics/measures/continuous/gaussian/SInfoCalculatorGaussianTester.java
diff --git a/java/source/infodynamics/measures/continuous/gaussian/DualTotalCorrelationCalculatorGaussian.java b/java/source/infodynamics/measures/continuous/gaussian/DualTotalCorrelationCalculatorGaussian.java
new file mode 100644
index 0000000..7d3c572
--- /dev/null
+++ b/java/source/infodynamics/measures/continuous/gaussian/DualTotalCorrelationCalculatorGaussian.java
@@ -0,0 +1,122 @@
+/*
+ * Java Information Dynamics Toolkit (JIDT)
+ * Copyright (C) 2017, Joseph T. Lizier, Ipek Oezdemir and Pedro Mediano
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package infodynamics.measures.continuous.gaussian;
+
+import infodynamics.utils.MatrixUtils;
+
+/**
+ * Computes the differential dual total correlation (DTC) of a given multivariate
+ * double[][] set of
+ * observations (extending {@link MultiVariateInfoMeasureCalculatorGaussian}),
+ * assuming that the probability distribution function for these observations is
+ * a multivariate Gaussian distribution.
+ *
+ * Usage is as per the paradigm outlined for {@link MultiVariateInfoMeasureCalculatorCommon}.
+ *
+ *
+ * References:
+ *
+ * - Rosas, F., Mediano, P., Gastpar, M, Jensen, H.,
+ * "Quantifying high-order
+ * interdependencies via multivariate extensions of the mutual information",
+ * Physical Review E 100, (2019) 032305.
+ *
+ *
+ * @author Pedro A.M. Mediano (email,
+ * www)
+ */
+public class DualTotalCorrelationCalculatorGaussian
+ extends MultiVariateInfoMeasureCalculatorGaussian {
+
+ /**
+ * Constructor.
+ */
+ public DualTotalCorrelationCalculatorGaussian() {
+ // Nothing to do
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return the average DTC in nats (not bits!)
+ * @throws Exception if not sufficient data have been provided, or if the
+ * supplied covariance matrix is invalid.
+ */
+ public double computeAverageLocalOfObservations() throws Exception {
+
+ if (covariance == null) {
+ throw new Exception("Cannot calculate DTC without having " +
+ "a covariance either supplied or computed via setObservations()");
+ }
+
+ if (!isComputed) {
+ double dtc = - (dimensions - 1)*Math.log(MatrixUtils.determinantSymmPosDefMatrix(covariance));
+ for (int i = 0; i < dimensions; i++) {
+ int[] idx = allExcept(i, dimensions);
+ double[][] marginal_cov = MatrixUtils.selectRowsAndColumns(covariance, idx, idx);
+ dtc += Math.log(MatrixUtils.determinantSymmPosDefMatrix(marginal_cov));
+ }
+ // This "0.5" comes from the entropy formula for Gaussians: h = 0.5*logdet(2*pi*e*Sigma)
+ lastAverage = 0.5*dtc;;
+ isComputed = true;
+ }
+
+ return lastAverage;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return the "time-series" of local DTC values in nats (not bits!)
+ * for the supplied states.
+ * @throws Exception if not sufficient data have been provided, or if the
+ * supplied covariance matrix is invalid.
+ */
+ public double[] computeLocalUsingPreviousObservations(double[][] states) throws Exception {
+
+ if ((means == null) || (covariance == null)) {
+ throw new Exception("Cannot compute local values without having means " +
+ "and covariance either supplied or computed via setObservations()");
+ }
+
+ EntropyCalculatorMultiVariateGaussian hCalc = new EntropyCalculatorMultiVariateGaussian();
+ hCalc.initialise(dimensions);
+ hCalc.setCovarianceAndMeans(covariance, means);
+ double[] localValues = MatrixUtils.multiply(hCalc.computeLocalUsingPreviousObservations(states), -(dimensions - 1));
+
+ for (int i = 0; i < dimensions; i++) {
+ int[] idx = allExcept(i, dimensions);
+ double[][] marginal_cov = MatrixUtils.selectRowsAndColumns(covariance, idx, idx);
+ double[] marginal_means = MatrixUtils.select(means, idx);
+ double[][] marginal_state = MatrixUtils.selectColumns(states, idx);
+
+ hCalc.initialise(dimensions - 1);
+ hCalc.setCovarianceAndMeans(marginal_cov, marginal_means);
+ double[] thisLocals = hCalc.computeLocalUsingPreviousObservations(marginal_state);
+
+ localValues = MatrixUtils.add(localValues, thisLocals);
+
+ }
+
+ return localValues;
+
+ }
+
+}
+
diff --git a/java/source/infodynamics/measures/continuous/gaussian/MultiVariateInfoMeasureCalculatorGaussian.java b/java/source/infodynamics/measures/continuous/gaussian/MultiVariateInfoMeasureCalculatorGaussian.java
new file mode 100644
index 0000000..f8d0933
--- /dev/null
+++ b/java/source/infodynamics/measures/continuous/gaussian/MultiVariateInfoMeasureCalculatorGaussian.java
@@ -0,0 +1,152 @@
+/*
+ * Java Information Dynamics Toolkit (JIDT)
+ * Copyright (C) 2017, Joseph T. Lizier, Ipek Oezdemir and Pedro Mediano
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package infodynamics.measures.continuous.gaussian;
+
+import infodynamics.measures.continuous.MultiVariateInfoMeasureCalculatorCommon;
+import infodynamics.utils.MatrixUtils;
+
+/**
+ * Base class with common functionality for child class implementations of
+ * multivariate information measures on a given multivariate
+ * double[][] set of
+ * observations (extending {@link MultiVariateInfoMeasureCalculatorCommon}),
+ * assuming that the probability distribution function for these observations is
+ * a multivariate Gaussian distribution.
+ *
+ * Usage is as per the paradigm outlined for {@link MultiVariateInfoMeasureCalculatorCommon},
+ * with:
+ *
+ * - For constructors see the child classes.
+ * - Further properties are defined in {@link #setProperty(String, String)}.
+ * - Computed values are in nats, not bits!
+ *
+ *
+ *
+ * References:
+ *
+ * - Rosas, F., Mediano, P., Gastpar, M, Jensen, H.,
+ * "Quantifying high-order
+ * interdependencies via multivariate extensions of the mutual information",
+ * Physical Review E 100, (2019) 032305.
+ *
+ *
+ * @author Pedro A.M. Mediano (email,
+ * www)
+ */
+public abstract class MultiVariateInfoMeasureCalculatorGaussian
+ extends MultiVariateInfoMeasureCalculatorCommon {
+
+ /**
+ * Covariance of the system. Can be calculated from supplied observations
+ * or supplied directly by the user.
+ */
+ double[][] covariance = null;
+
+ /**
+ * Means of the system. Can be calculated from supplied observations
+ * or supplied directly by the user.
+ */
+ double[] means = null;
+
+ /**
+ * Whether the current covariance matrix has been determined from data or
+ * supplied directly. This changes the approach to local measures and
+ * significance testing.
+ */
+ boolean covFromObservations;
+
+ @Override
+ public void finaliseAddObservations() throws Exception {
+ super.finaliseAddObservations();
+
+ this.means = MatrixUtils.means(observations);
+ setCovariance(MatrixUtils.covarianceMatrix(observations), true);
+
+ return;
+ }
+
+ /**
+ * Set the covariance of the distribution for which we will compute the
+ * measure directly, without supplying observations.
+ *
+ * See {@link #setCovariance(double[][], boolean)}.
+ *
+ * @param covariance covariance matrix of the system
+ * @throws Exception for covariance matrix not matching the expected dimensions,
+ * being non-square, asymmetric or non-positive definite
+ */
+ public void setCovariance(double[][] covariance) throws Exception {
+ setCovariance(covariance, false);
+ }
+
+ /**
+ *
Set the covariance of the distribution for which we will compute the
+ * measure.
+ *
+ * This is an alternative to sequences of calls to {@link #setObservations(double[][])} or
+ * {@link #addObservations(double[][])} etc.
+ * Note that without setting any observations, you cannot later
+ * call {@link #computeLocalOfPreviousObservations()}.
+ *
+ * @param covariance covariance matrix of the system
+ * @param means mean of the system
+ */
+ public void setCovarianceAndMeans(double[][] covariance, double[] means)
+ throws Exception {
+ this.means = means;
+ setCovariance(covariance, false);
+ }
+
+ /**
+ * Set the covariance of the distribution for which we will compute the
+ * measure.
+ *
+ * This is an alternative to sequences of calls to {@link #setObservations(double[][])} or
+ * {@link #addObservations(double[][])} etc.
+ * Note that without setting any observations, you cannot later
+ * call {@link #computeLocalOfPreviousObservations()}, and without
+ * providing the means of the variables, you cannot later call
+ * {@link #computeLocalUsingPreviousObservations(double[][])}.
+ *
+ * @param covariance covariance matrix of the system
+ * @param covFromObservations whether the covariance matrix
+ * was determined internally from observations or not
+ * @throws Exception for covariance matrix not matching the expected dimensions,
+ * being non-square, asymmetric or non-positive definite
+ */
+ public void setCovariance(double[][] cov, boolean covFromObservations) throws Exception {
+
+ if (!covFromObservations) {
+ // Make sure we're not keeping any observations
+ observations = null;
+ }
+ if (cov.length != dimensions) {
+ throw new Exception("Supplied covariance matrix does not match initialised number of dimensions");
+ }
+ if (cov.length != cov[0].length) {
+ throw new Exception("Covariance matrices must be square");
+ }
+
+ this.covFromObservations = covFromObservations;
+ this.covariance = cov;
+
+ }
+
+}
+
diff --git a/java/source/infodynamics/measures/continuous/gaussian/OInfoCalculatorGaussian.java b/java/source/infodynamics/measures/continuous/gaussian/OInfoCalculatorGaussian.java
new file mode 100644
index 0000000..83c75dc
--- /dev/null
+++ b/java/source/infodynamics/measures/continuous/gaussian/OInfoCalculatorGaussian.java
@@ -0,0 +1,134 @@
+/*
+ * Java Information Dynamics Toolkit (JIDT)
+ * Copyright (C) 2017, Joseph T. Lizier, Ipek Oezdemir and Pedro Mediano
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package infodynamics.measures.continuous.gaussian;
+
+import infodynamics.utils.MatrixUtils;
+
+/**
+ * Computes the differential O-information of a given multivariate
+ * double[][] set of
+ * observations (extending {@link MultiVariateInfoMeasureCalculatorGaussian}),
+ * assuming that the probability distribution function for these observations is
+ * a multivariate Gaussian distribution.
+ *
+ * Usage is as per the paradigm outlined for {@link MultiVariateInfoMeasureCalculatorCommon}.
+ *
+ *
+ * References:
+ *
+ * - Rosas, F., Mediano, P., Gastpar, M, Jensen, H.,
+ * "Quantifying high-order
+ * interdependencies via multivariate extensions of the mutual information",
+ * Physical Review E 100, (2019) 032305.
+ *
+ *
+ * @author Pedro A.M. Mediano (email,
+ * www)
+ */
+public class OInfoCalculatorGaussian
+ extends MultiVariateInfoMeasureCalculatorGaussian {
+
+ /**
+ * Constructor.
+ */
+ public OInfoCalculatorGaussian() {
+ // Nothing to do
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return the average O-info in nats (not bits!)
+ * @throws Exception if not sufficient data have been provided, or if the
+ * supplied covariance matrix is invalid.
+ */
+ public double computeAverageLocalOfObservations() throws Exception {
+
+ if (covariance == null) {
+ throw new Exception("Cannot calculate O-Info without having " +
+ "a covariance either supplied or computed via setObservations()");
+ }
+
+ if (!isComputed) {
+ double oinfo = (dimensions - 2)*Math.log(MatrixUtils.determinantSymmPosDefMatrix(covariance));
+ for (int i = 0; i < dimensions; i++) {
+ int[] idx = allExcept(i, dimensions);
+ double[][] marginal_cov = MatrixUtils.selectRowsAndColumns(covariance, idx, idx);
+ oinfo += Math.log(covariance[i][i]) - Math.log(MatrixUtils.determinantSymmPosDefMatrix(marginal_cov));
+ }
+ // This "0.5" comes from the entropy formula for Gaussians: h = 0.5*logdet(2*pi*e*Sigma)
+ lastAverage = 0.5*oinfo;;
+ isComputed = true;
+ }
+
+ return lastAverage;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return the "time-series" of local O-info values in nats (not bits!)
+ * for the supplied states.
+ * @throws Exception if not sufficient data have been provided, or if the
+ * supplied covariance matrix is invalid.
+ */
+ public double[] computeLocalUsingPreviousObservations(double[][] states) throws Exception {
+
+ if ((means == null) || (covariance == null)) {
+ throw new Exception("Cannot compute local values without having means " +
+ "and covariance either supplied or computed via setObservations()");
+ }
+
+ EntropyCalculatorMultiVariateGaussian hCalc = new EntropyCalculatorMultiVariateGaussian();
+ hCalc.initialise(dimensions);
+ hCalc.setCovarianceAndMeans(covariance, means);
+ double[] localValues = MatrixUtils.multiply(hCalc.computeLocalUsingPreviousObservations(states), dimensions - 2);
+
+ for (int i = 0; i < dimensions; i++) {
+ int[] idx = allExcept(i, dimensions);
+
+ // Local entropy of this variable (i) only
+ double[][] this_cov = MatrixUtils.selectRowsAndColumns(covariance, i, 1, i, 1);
+ double[] this_means = MatrixUtils.select(means, i, 1);
+ double[][] this_state = MatrixUtils.selectColumns(states, i, 1);
+
+ hCalc.initialise(1);
+ hCalc.setCovarianceAndMeans(this_cov, this_means);
+ double[] thisLocals = hCalc.computeLocalUsingPreviousObservations(this_state);
+
+ // Local entropy of the rest of the variables (0, ... i-1, i+1, ... D)
+ double[][] rest_cov = MatrixUtils.selectRowsAndColumns(covariance, idx, idx);
+ double[] rest_means = MatrixUtils.select(means, idx);
+ double[][] rest_state = MatrixUtils.selectColumns(states, idx);
+
+ hCalc.initialise(dimensions - 1);
+ hCalc.setCovarianceAndMeans(rest_cov, rest_means);
+ double[] restLocals = hCalc.computeLocalUsingPreviousObservations(rest_state);
+
+ localValues = MatrixUtils.add(localValues, MatrixUtils.subtract(thisLocals, restLocals));
+
+ }
+
+ return localValues;
+
+ }
+
+}
+
+
diff --git a/java/source/infodynamics/measures/continuous/gaussian/SInfoCalculatorGaussian.java b/java/source/infodynamics/measures/continuous/gaussian/SInfoCalculatorGaussian.java
new file mode 100644
index 0000000..02c5627
--- /dev/null
+++ b/java/source/infodynamics/measures/continuous/gaussian/SInfoCalculatorGaussian.java
@@ -0,0 +1,120 @@
+/*
+ * Java Information Dynamics Toolkit (JIDT)
+ * Copyright (C) 2017, Joseph T. Lizier, Ipek Oezdemir and Pedro Mediano
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package infodynamics.measures.continuous.gaussian;
+
+import infodynamics.utils.MatrixUtils;
+
+/**
+ * Computes the differential S-information of a given multivariate
+ * double[][] set of
+ * observations (extending {@link MultiVariateInfoMeasureCalculatorGaussian}),
+ * assuming that the probability distribution function for these observations is
+ * a multivariate Gaussian distribution.
+ *
+ * Usage is as per the paradigm outlined for {@link MultiVariateInfoMeasureCalculatorCommon}.
+ *
+ *
+ * References:
+ *
+ * - Rosas, F., Mediano, P., Gastpar, M, Jensen, H.,
+ * "Quantifying high-order
+ * interdependencies via multivariate extensions of the mutual information",
+ * Physical Review E 100, (2019) 032305.
+ *
+ *
+ * @author Pedro A.M. Mediano (email,
+ * www)
+ */
+public class SInfoCalculatorGaussian
+ extends MultiVariateInfoMeasureCalculatorGaussian {
+
+ /**
+ * Constructor.
+ */
+ public SInfoCalculatorGaussian() {
+ // Nothing to do
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return the average S-info in nats (not bits!)
+ * @throws Exception if not sufficient data have been provided, or if the
+ * supplied covariance matrix is invalid.
+ */
+ public double computeAverageLocalOfObservations() throws Exception {
+
+ if (covariance == null) {
+ throw new Exception("Cannot calculate O-Info without having " +
+ "a covariance either supplied or computed via setObservations()");
+ }
+
+ if (!isComputed) {
+
+ MultiInfoCalculatorGaussian tcCalc = new MultiInfoCalculatorGaussian();
+ tcCalc.initialise(dimensions);
+ tcCalc.setCovariance(covariance);
+ double tc = tcCalc.computeAverageLocalOfObservations();
+
+ DualTotalCorrelationCalculatorGaussian dtcCalc = new DualTotalCorrelationCalculatorGaussian();
+ dtcCalc.initialise(dimensions);
+ dtcCalc.setCovariance(covariance);
+ double dtc = dtcCalc.computeAverageLocalOfObservations();
+
+ lastAverage = tc + dtc;
+ isComputed = true;
+ }
+
+ return lastAverage;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return the "time-series" of local S-info values in nats (not bits!)
+ * for the supplied states.
+ * @throws Exception if not sufficient data have been provided, or if the
+ * supplied covariance matrix is invalid.
+ */
+ public double[] computeLocalUsingPreviousObservations(double[][] states) throws Exception {
+
+ if ((means == null) || (covariance == null)) {
+ throw new Exception("Cannot compute local values without having means " +
+ "and covariance either supplied or computed via setObservations()");
+ }
+
+ MultiInfoCalculatorGaussian tcCalc = new MultiInfoCalculatorGaussian();
+ tcCalc.initialise(dimensions);
+ tcCalc.setCovarianceAndMeans(covariance, means);
+ double[] localTC = tcCalc.computeLocalUsingPreviousObservations(states);
+
+ DualTotalCorrelationCalculatorGaussian dtcCalc = new DualTotalCorrelationCalculatorGaussian();
+ dtcCalc.initialise(dimensions);
+ dtcCalc.setCovarianceAndMeans(covariance, means);
+ double[] localDTC = dtcCalc.computeLocalUsingPreviousObservations(states);
+
+ double[] localValues = MatrixUtils.add(localTC, localDTC);
+
+ return localValues;
+
+ }
+
+}
+
+
diff --git a/java/unittests/infodynamics/measures/continuous/gaussian/DualTotalCorrelationCalculatorGaussianTester.java b/java/unittests/infodynamics/measures/continuous/gaussian/DualTotalCorrelationCalculatorGaussianTester.java
new file mode 100644
index 0000000..a5cd702
--- /dev/null
+++ b/java/unittests/infodynamics/measures/continuous/gaussian/DualTotalCorrelationCalculatorGaussianTester.java
@@ -0,0 +1,133 @@
+/*
+ * Java Information Dynamics Toolkit (JIDT)
+ * Copyright (C) 2012, Joseph T. Lizier
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package infodynamics.measures.continuous.gaussian;
+
+import infodynamics.utils.MatrixUtils;
+import infodynamics.utils.RandomGenerator;
+import junit.framework.TestCase;
+
+public class DualTotalCorrelationCalculatorGaussianTester extends TestCase {
+
+ /**
+ * For two variables, DTC is equal to mutual information.
+ */
+ public void testTwoVariables() throws Exception {
+ double[][] cov = new double[][] {{1, 0.5}, {0.5, 1}};
+
+ DualTotalCorrelationCalculatorGaussian dtcCalc = new DualTotalCorrelationCalculatorGaussian();
+ dtcCalc.initialise(2);
+ dtcCalc.setCovariance(cov);
+ double dtc = dtcCalc.computeAverageLocalOfObservations();
+
+ MutualInfoCalculatorMultiVariateGaussian miCalc = new MutualInfoCalculatorMultiVariateGaussian();
+ miCalc.initialise(1,1);
+ miCalc.setCovariance(cov, 1);
+ double mi = miCalc.computeAverageLocalOfObservations();
+
+ assertEquals(dtc, mi, 1e-6);
+ }
+
+ /**
+ * Compare against the direct calculation of DTC as a sum of entropies using the
+ * entropy calculator.
+ */
+ public void testCompareWithEntropy() throws Exception {
+ double[][] cov = new double[][] {{1, 0.4, 0.3}, {0.4, 1, 0.2}, {0.3, 0.2, 1}};
+
+ DualTotalCorrelationCalculatorGaussian dtcCalc = new DualTotalCorrelationCalculatorGaussian();
+ dtcCalc.initialise(3);
+ dtcCalc.setCovariance(cov);
+ double dtc = dtcCalc.computeAverageLocalOfObservations();
+
+ // Calculate using an entropy calculator and picking submatrices manually
+ EntropyCalculatorMultiVariateGaussian hCalc = new EntropyCalculatorMultiVariateGaussian();
+ hCalc.initialise(3);
+ hCalc.setCovariance(cov);
+ double dtc_hCalc = -2 * hCalc.computeAverageLocalOfObservations();
+
+ hCalc.initialise(2);
+ hCalc.setCovariance(MatrixUtils.selectRowsAndColumns(cov, new int[] {0,1}, new int[] {0,1}));
+ dtc_hCalc += hCalc.computeAverageLocalOfObservations();
+ hCalc.initialise(2);
+ hCalc.setCovariance(MatrixUtils.selectRowsAndColumns(cov, new int[] {0,2}, new int[] {0,2}));
+ dtc_hCalc += hCalc.computeAverageLocalOfObservations();
+ hCalc.initialise(2);
+ hCalc.setCovariance(MatrixUtils.selectRowsAndColumns(cov, new int[] {1,2}, new int[] {1,2}));
+ dtc_hCalc += hCalc.computeAverageLocalOfObservations();
+
+ assertEquals(dtc, dtc_hCalc, 1e-6);
+
+ }
+
+ /**
+ * Confirm that the local values average correctly back to the average value
+ */
+ public void testLocalsAverageCorrectly() throws Exception {
+
+ int dimensions = 4;
+ int timeSteps = 1000;
+ DualTotalCorrelationCalculatorGaussian dtcCalc = new DualTotalCorrelationCalculatorGaussian();
+ dtcCalc.initialise(dimensions);
+
+ // generate some random data
+ RandomGenerator rg = new RandomGenerator();
+ double[][] data = rg.generateNormalData(timeSteps, dimensions,
+ 0, 1);
+
+ dtcCalc.setObservations(data);
+
+ double dtc = dtcCalc.computeAverageLocalOfObservations();
+ double[] dtcLocal = dtcCalc.computeLocalOfPreviousObservations();
+
+ System.out.printf("Average was %.5f\n", dtc);
+
+ assertEquals(dtc, MatrixUtils.mean(dtcLocal), 0.00001);
+ }
+
+ /**
+ * Confirm that for 2D the local values equal the local MI values
+ *
+ */
+ public void testLocalsEqualMI() throws Exception {
+
+ int dimensions = 2;
+ int timeSteps = 100;
+ DualTotalCorrelationCalculatorGaussian dtcCalc = new DualTotalCorrelationCalculatorGaussian();
+ dtcCalc.initialise(dimensions);
+
+ // generate some random data
+ RandomGenerator rg = new RandomGenerator();
+ double[][] data = rg.generateNormalData(timeSteps, dimensions,
+ 0, 1);
+
+ dtcCalc.setObservations(data);
+ double[] dtcLocal = dtcCalc.computeLocalOfPreviousObservations();
+
+ MutualInfoCalculatorMultiVariateGaussian miCalc = new MutualInfoCalculatorMultiVariateGaussian();
+ miCalc.initialise(1, 1);
+ miCalc.setObservations(MatrixUtils.selectColumn(data, 0), MatrixUtils.selectColumn(data, 1));
+ double[] miLocal = miCalc.computeLocalOfPreviousObservations();
+
+ for (int t = 0; t < timeSteps; t++) {
+ assertEquals(dtcLocal[t], miLocal[t], 0.00001);
+ }
+ }
+
+}
+
diff --git a/java/unittests/infodynamics/measures/continuous/gaussian/OInfoCalculatorGaussianTester.java b/java/unittests/infodynamics/measures/continuous/gaussian/OInfoCalculatorGaussianTester.java
new file mode 100644
index 0000000..15e3c46
--- /dev/null
+++ b/java/unittests/infodynamics/measures/continuous/gaussian/OInfoCalculatorGaussianTester.java
@@ -0,0 +1,150 @@
+/*
+ * Java Information Dynamics Toolkit (JIDT)
+ * Copyright (C) 2012, Joseph T. Lizier
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package infodynamics.measures.continuous.gaussian;
+
+import infodynamics.utils.MatrixUtils;
+import infodynamics.utils.RandomGenerator;
+import junit.framework.TestCase;
+
+public class OInfoCalculatorGaussianTester extends TestCase {
+
+ /**
+ * For two variables, O-info is zero
+ */
+ public void testTwoVariables() throws Exception {
+ double[][] cov = new double[][] {{1, 0.5}, {0.5, 1}};
+
+ OInfoCalculatorGaussian oCalc = new OInfoCalculatorGaussian();
+ oCalc.initialise(2);
+ oCalc.setCovariance(cov);
+ double oinfo = oCalc.computeAverageLocalOfObservations();
+
+ assertEquals(oinfo, 0, 1e-6);
+ }
+
+
+ /**
+ * For factorisable pairwise interactions, O-info is zero
+ */
+ public void testPairwise() throws Exception {
+ double[][] cov = new double[][] {{ 1, 0.5, 0, 0},
+ {0.5, 1, 0, 0},
+ { 0, 0, 1, 0.5},
+ { 0, 0, 0.5, 1}};
+
+ OInfoCalculatorGaussian oCalc = new OInfoCalculatorGaussian();
+ oCalc.initialise(4);
+ oCalc.setCovariance(cov);
+ double oinfo = oCalc.computeAverageLocalOfObservations();
+
+ assertEquals(oinfo, 0, 1e-6);
+ }
+
+ /**
+ * Compare against the direct calculation of O-info as a sum of entropies using the
+ * entropy calculator.
+ */
+ public void testCompareWithEntropy() throws Exception {
+ double[][] cov = new double[][] {{1, 0.4, 0.3}, {0.4, 1, 0.2}, {0.3, 0.2, 1}};
+
+ OInfoCalculatorGaussian oCalc = new OInfoCalculatorGaussian();
+ oCalc.initialise(3);
+ oCalc.setCovariance(cov);
+ double oinfo = oCalc.computeAverageLocalOfObservations();
+
+ // Calculate using an entropy calculator and picking submatrices manually
+ EntropyCalculatorMultiVariateGaussian hCalc = new EntropyCalculatorMultiVariateGaussian();
+ hCalc.initialise(3);
+ hCalc.setCovariance(cov);
+ double oinfo_hCalc = hCalc.computeAverageLocalOfObservations();
+
+ hCalc.initialise(2);
+ hCalc.setCovariance(MatrixUtils.selectRowsAndColumns(cov, new int[] {0,1}, new int[] {0,1}));
+ oinfo_hCalc -= hCalc.computeAverageLocalOfObservations();
+ hCalc.initialise(2);
+ hCalc.setCovariance(MatrixUtils.selectRowsAndColumns(cov, new int[] {0,2}, new int[] {0,2}));
+ oinfo_hCalc -= hCalc.computeAverageLocalOfObservations();
+ hCalc.initialise(2);
+ hCalc.setCovariance(MatrixUtils.selectRowsAndColumns(cov, new int[] {1,2}, new int[] {1,2}));
+ oinfo_hCalc -= hCalc.computeAverageLocalOfObservations();
+
+ hCalc.initialise(1);
+ hCalc.setCovariance(new double[][] {{cov[0][0]}});
+ oinfo_hCalc += hCalc.computeAverageLocalOfObservations();
+ hCalc.initialise(1);
+ hCalc.setCovariance(new double[][] {{cov[1][1]}});
+ oinfo_hCalc += hCalc.computeAverageLocalOfObservations();
+ hCalc.initialise(1);
+ hCalc.setCovariance(new double[][] {{cov[2][2]}});
+ oinfo_hCalc += hCalc.computeAverageLocalOfObservations();
+
+ assertEquals(oinfo, oinfo_hCalc, 1e-6);
+
+ }
+
+ /**
+ * Confirm that the local values average correctly back to the average value
+ */
+ public void testLocalsAverageCorrectly() throws Exception {
+
+ int dimensions = 4;
+ int timeSteps = 1000;
+ OInfoCalculatorGaussian oCalc = new OInfoCalculatorGaussian();
+ oCalc.initialise(dimensions);
+
+ // generate some random data
+ RandomGenerator rg = new RandomGenerator();
+ double[][] data = rg.generateNormalData(timeSteps, dimensions,
+ 0, 1);
+
+ oCalc.setObservations(data);
+
+ double oinfo = oCalc.computeAverageLocalOfObservations();
+ double[] oLocal = oCalc.computeLocalOfPreviousObservations();
+
+ System.out.printf("Average was %.5f\n", oinfo);
+
+ assertEquals(oinfo, MatrixUtils.mean(oLocal), 0.00001);
+ }
+
+ /**
+ * Confirm that for 2D all local values equal zero
+ */
+ public void testLocalsEqualZero() throws Exception {
+
+ int dimensions = 2;
+ int timeSteps = 100;
+ OInfoCalculatorGaussian oCalc = new OInfoCalculatorGaussian();
+ oCalc.initialise(dimensions);
+
+ // generate some random data
+ RandomGenerator rg = new RandomGenerator();
+ double[][] data = rg.generateNormalData(timeSteps, dimensions,
+ 0, 1);
+
+ oCalc.setObservations(data);
+ double[] oLocal = oCalc.computeLocalOfPreviousObservations();
+
+ for (int t = 0; t < timeSteps; t++) {
+ assertEquals(oLocal[t], 0, 0.00001);
+ }
+ }
+
+}
+
diff --git a/java/unittests/infodynamics/measures/continuous/gaussian/SInfoCalculatorGaussianTester.java b/java/unittests/infodynamics/measures/continuous/gaussian/SInfoCalculatorGaussianTester.java
new file mode 100644
index 0000000..bc33ad7
--- /dev/null
+++ b/java/unittests/infodynamics/measures/continuous/gaussian/SInfoCalculatorGaussianTester.java
@@ -0,0 +1,129 @@
+/*
+ * Java Information Dynamics Toolkit (JIDT)
+ * Copyright (C) 2012, Joseph T. Lizier
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package infodynamics.measures.continuous.gaussian;
+
+import infodynamics.utils.MatrixUtils;
+import infodynamics.utils.RandomGenerator;
+import junit.framework.TestCase;
+
+public class SInfoCalculatorGaussianTester extends TestCase {
+
+ /**
+ * For two variables, S-info is twice the MI between them
+ */
+ public void testTwoVariables() throws Exception {
+ double[][] cov = new double[][] {{1, 0.5}, {0.5, 1}};
+
+ SInfoCalculatorGaussian sCalc = new SInfoCalculatorGaussian();
+ sCalc.initialise(2);
+ sCalc.setCovariance(cov);
+ double sinfo = sCalc.computeAverageLocalOfObservations();
+
+ MutualInfoCalculatorMultiVariateGaussian miCalc = new MutualInfoCalculatorMultiVariateGaussian();
+ miCalc.initialise(1,1);
+ miCalc.setCovariance(cov, false);
+ double mi = miCalc.computeAverageLocalOfObservations();
+
+ assertEquals(sinfo, 2*mi, 1e-6);
+ }
+
+
+ /**
+ * Compare against the direct calculation of S-info as a sum of mutual informations.
+ */
+ public void testCompareWithEntropy() throws Exception {
+ double[][] cov = new double[][] {{1, 0.4, 0.3}, {0.4, 1, 0.2}, {0.3, 0.2, 1}};
+
+ SInfoCalculatorGaussian sCalc = new SInfoCalculatorGaussian();
+ sCalc.initialise(3);
+ sCalc.setCovariance(cov);
+ double sinfo = sCalc.computeAverageLocalOfObservations();
+
+ // Calculate using a mutual info calculator and picking submatrices manually
+ MutualInfoCalculatorMultiVariateGaussian miCalc = new MutualInfoCalculatorMultiVariateGaussian();
+ miCalc.initialise(2,1);
+ miCalc.setCovariance(cov, false);
+ double sinfo_miCalc = miCalc.computeAverageLocalOfObservations();
+
+ miCalc.initialise(2,1);
+ miCalc.setCovariance(MatrixUtils.selectRowsAndColumns(cov, new int[] {2,0,1}, new int[] {2,0,1}), false);
+ sinfo_miCalc += miCalc.computeAverageLocalOfObservations();
+ miCalc.initialise(2,1);
+ miCalc.setCovariance(MatrixUtils.selectRowsAndColumns(cov, new int[] {1,2,0}, new int[] {1,2,0}), false);
+ sinfo_miCalc += miCalc.computeAverageLocalOfObservations();
+
+ assertEquals(sinfo, sinfo_miCalc, 1e-6);
+
+ }
+
+ /**
+ * Confirm that the local values average correctly back to the average value
+ */
+ public void testLocalsAverageCorrectly() throws Exception {
+
+ int dimensions = 4;
+ int timeSteps = 1000;
+ SInfoCalculatorGaussian sCalc = new SInfoCalculatorGaussian();
+ sCalc.initialise(dimensions);
+
+ // generate some random data
+ RandomGenerator rg = new RandomGenerator();
+ double[][] data = rg.generateNormalData(timeSteps, dimensions,
+ 0, 1);
+
+ sCalc.setObservations(data);
+
+ double sinfo = sCalc.computeAverageLocalOfObservations();
+ double[] sLocal = sCalc.computeLocalOfPreviousObservations();
+
+ System.out.printf("Average was %.5f\n", sinfo);
+
+ assertEquals(sinfo, MatrixUtils.mean(sLocal), 0.00001);
+ }
+
+ /**
+ * Confirm that for 2D all local values equal zero
+ */
+ public void testLocalsEqualMI() throws Exception {
+
+ int dimensions = 2;
+ int timeSteps = 100;
+ SInfoCalculatorGaussian sCalc = new SInfoCalculatorGaussian();
+ sCalc.initialise(dimensions);
+
+ // generate some random data
+ RandomGenerator rg = new RandomGenerator();
+ double[][] data = rg.generateNormalData(timeSteps, dimensions,
+ 0, 1);
+
+ sCalc.setObservations(data);
+ double[] sLocal = sCalc.computeLocalOfPreviousObservations();
+
+ MutualInfoCalculatorMultiVariateGaussian miCalc = new MutualInfoCalculatorMultiVariateGaussian();
+ miCalc.initialise(1, 1);
+ miCalc.setObservations(MatrixUtils.selectColumn(data, 0), MatrixUtils.selectColumn(data, 1));
+ double[] miLocal = miCalc.computeLocalOfPreviousObservations();
+
+ for (int t = 0; t < timeSteps; t++) {
+ assertEquals(sLocal[t], 2*miLocal[t], 0.00001);
+ }
+ }
+
+}
+