Added Gaussian implementation of various multivariate IT measures and unit tests.

This commit is contained in:
Pedro Mediano 2021-01-24 22:06:39 +00:00
parent 403745800e
commit f67e274819
7 changed files with 940 additions and 0 deletions

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
package infodynamics.measures.continuous.gaussian;
import infodynamics.utils.MatrixUtils;
/**
* <p>Computes the differential dual total correlation (DTC) of a given multivariate
* <code>double[][]</code> set of
* observations (extending {@link MultiVariateInfoMeasureCalculatorGaussian}),
* assuming that the probability distribution function for these observations is
* a multivariate Gaussian distribution.</p>
*
* <p>Usage is as per the paradigm outlined for {@link MultiVariateInfoMeasureCalculatorCommon}.
* </p>
*
* <p><b>References:</b><br/>
* <ul>
* <li>Rosas, F., Mediano, P., Gastpar, M, Jensen, H.,
* <a href="http://dx.doi.org/10.1103/PhysRevE.100.032305">"Quantifying high-order
* interdependencies via multivariate extensions of the mutual information"</a>,
* Physical Review E 100, (2019) 032305.</li>
* </ul>
*
* @author Pedro A.M. Mediano (<a href="pmediano at pm.me">email</a>,
* <a href="http://www.doc.ic.ac.uk/~pam213">www</a>)
*/
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
package infodynamics.measures.continuous.gaussian;
import infodynamics.measures.continuous.MultiVariateInfoMeasureCalculatorCommon;
import infodynamics.utils.MatrixUtils;
/**
* <p>Base class with common functionality for child class implementations of
* multivariate information measures on a given multivariate
* <code>double[][]</code> set of
* observations (extending {@link MultiVariateInfoMeasureCalculatorCommon}),
* assuming that the probability distribution function for these observations is
* a multivariate Gaussian distribution.</p>
*
* <p>Usage is as per the paradigm outlined for {@link MultiVariateInfoMeasureCalculatorCommon},
* with:
* <ul>
* <li>For constructors see the child classes.</li>
* <li>Further properties are defined in {@link #setProperty(String, String)}.</li>
* <li>Computed values are in <b>nats</b>, not bits!</li>
* </ul>
* </p>
*
* <p><b>References:</b><br/>
* <ul>
* <li>Rosas, F., Mediano, P., Gastpar, M, Jensen, H.,
* <a href="http://dx.doi.org/10.1103/PhysRevE.100.032305">"Quantifying high-order
* interdependencies via multivariate extensions of the mutual information"</a>,
* Physical Review E 100, (2019) 032305.</li>
* </ul>
*
* @author Pedro A.M. Mediano (<a href="pmediano at pm.me">email</a>,
* <a href="http://www.doc.ic.ac.uk/~pam213">www</a>)
*/
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;
}
/**
* <p>Set the covariance of the distribution for which we will compute the
* measure directly, without supplying observations.</p>
*
* <p>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);
}
/**
* <p>Set the covariance of the distribution for which we will compute the
* measure.</p>
*
* <p>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()}.</p>
*
* @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);
}
/**
* <p>Set the covariance of the distribution for which we will compute the
* measure.</p>
*
* <p>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[][])}.</p>
*
* @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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
package infodynamics.measures.continuous.gaussian;
import infodynamics.utils.MatrixUtils;
/**
* <p>Computes the differential O-information of a given multivariate
* <code>double[][]</code> set of
* observations (extending {@link MultiVariateInfoMeasureCalculatorGaussian}),
* assuming that the probability distribution function for these observations is
* a multivariate Gaussian distribution.</p>
*
* <p>Usage is as per the paradigm outlined for {@link MultiVariateInfoMeasureCalculatorCommon}.
* </p>
*
* <p><b>References:</b><br/>
* <ul>
* <li>Rosas, F., Mediano, P., Gastpar, M, Jensen, H.,
* <a href="http://dx.doi.org/10.1103/PhysRevE.100.032305">"Quantifying high-order
* interdependencies via multivariate extensions of the mutual information"</a>,
* Physical Review E 100, (2019) 032305.</li>
* </ul>
*
* @author Pedro A.M. Mediano (<a href="pmediano at pm.me">email</a>,
* <a href="http://www.doc.ic.ac.uk/~pam213">www</a>)
*/
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
package infodynamics.measures.continuous.gaussian;
import infodynamics.utils.MatrixUtils;
/**
* <p>Computes the differential S-information of a given multivariate
* <code>double[][]</code> set of
* observations (extending {@link MultiVariateInfoMeasureCalculatorGaussian}),
* assuming that the probability distribution function for these observations is
* a multivariate Gaussian distribution.</p>
*
* <p>Usage is as per the paradigm outlined for {@link MultiVariateInfoMeasureCalculatorCommon}.
* </p>
*
* <p><b>References:</b><br/>
* <ul>
* <li>Rosas, F., Mediano, P., Gastpar, M, Jensen, H.,
* <a href="http://dx.doi.org/10.1103/PhysRevE.100.032305">"Quantifying high-order
* interdependencies via multivariate extensions of the mutual information"</a>,
* Physical Review E 100, (2019) 032305.</li>
* </ul>
*
* @author Pedro A.M. Mediano (<a href="pmediano at pm.me">email</a>,
* <a href="http://www.doc.ic.ac.uk/~pam213">www</a>)
*/
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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);
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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);
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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);
}
}
}