Patching linear Gaussian estimators to give empirical statistical significance given a certain number of observations.

Changed implementation of our conditional MI calculators Kraskov via algorithm 2 to my current interpretation of how this should be done.

Added a utility for lagged covariance in MatrixUtils
This commit is contained in:
joseph.lizier 2013-03-04 06:08:38 +00:00
parent 64f6986d45
commit cd67da53a4
7 changed files with 159 additions and 65 deletions

View File

@ -4,6 +4,7 @@ import infodynamics.measures.continuous.ConditionalMutualInfoCalculatorMultiVari
import infodynamics.measures.continuous.ConditionalMutualInfoMultiVariateCommon;
import infodynamics.utils.AnalyticNullDistributionComputer;
import infodynamics.utils.ChiSquareMeasurementDistribution;
import infodynamics.utils.EmpiricalMeasurementDistribution;
import infodynamics.utils.MatrixUtils;
/**
@ -145,11 +146,14 @@ public class ConditionalMutualInfoCalculatorMultiVariateGaussian
*
* @param covariance covariance matrix of var1, var2, conditional
* variables, considered together.
* @param numObservations the number of observations that the covariance
* was determined from. This is used for later significance calculations
* @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 {
public void setCovariance(double[][] covariance, int numObservations) throws Exception {
setCovariance(covariance, false);
totalObservations = numObservations;
}
/**
@ -222,10 +226,14 @@ public class ConditionalMutualInfoCalculatorMultiVariateGaussian
* variables, considered together.
* @param means mean of var1, var2 and conditional variables (as per
* covariance)
* @param numObservations the number of observations that the mean and covariance
* were determined from. This is used for later significance calculations
*/
public void setCovarianceAndMeans(double[][] covariance, double[] means) throws Exception {
public void setCovarianceAndMeans(double[][] covariance, double[] means,
int numObservations) throws Exception {
this.means = means;
setCovariance(covariance);
setCovariance(covariance, numObservations);
}
/**
@ -309,10 +317,40 @@ public class ConditionalMutualInfoCalculatorMultiVariateGaussian
// Number of extra parameters in the model incorporating the
// extra variable is independent of the number of variables
// in the conditional:
return new ChiSquareMeasurementDistribution(2*totalObservations*lastAverage,
return new ChiSquareMeasurementDistribution(2.0*((double)totalObservations)*lastAverage,
dimensionsVar1 * dimensionsVar2);
}
/* (non-Javadoc)
* @see infodynamics.measures.continuous.ConditionalMutualInfoMultiVariateCommon#computeSignificance(int, int)
*/
@Override
public EmpiricalMeasurementDistribution computeSignificance(
int variableToReorder, int numPermutationsToCheck) throws Exception {
if (var2Observations == null) {
throw new Exception("Cannot compute empirical statistical significance " +
"if user passed in covariance matrix rather than observations.");
}
return super.computeSignificance(variableToReorder, numPermutationsToCheck);
}
/* (non-Javadoc)
* @see infodynamics.measures.continuous.ConditionalMutualInfoMultiVariateCommon#computeSignificance(int, int[][])
*/
@Override
public EmpiricalMeasurementDistribution computeSignificance(
int variableToReorder, int[][] newOrderings) throws Exception {
if (var2Observations == null) {
throw new Exception("Cannot compute empirical statistical significance " +
"if user passed in covariance matrix rather than observations.");
}
return super.computeSignificance(variableToReorder, newOrderings);
}
/**
* @return the number of previously supplied observations for which
* the conditional mutual information will be / was computed.

View File

@ -147,11 +147,14 @@ public class MutualInfoCalculatorMultiVariateGaussian
* matrix of the source observations, C_dd is the covariance matrix
* of the destination observations, and C_sd and C_ds are the covariances
* of source to destination and destination to source observations.
* @param numObservations the number of observations that the covariance
* was determined from. This is used for later significance calculations
* @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 {
public void setCovariance(double[][] covariance, int numObservations) throws Exception {
setCovariance(covariance, false);
totalObservations = numObservations;
}
/**
@ -218,10 +221,13 @@ public class MutualInfoCalculatorMultiVariateGaussian
* and continue into the destination).
* @param means mean of the source and destination variables (as per
* covariance)
* @param numObservations the number of observations that the mean and covariance
* were determined from. This is used for later significance calculations
*/
public void setCovarianceAndMeans(double[][] covariance, double[] means) throws Exception {
public void setCovarianceAndMeans(double[][] covariance, double[] means,
int numObservations) throws Exception {
this.means = means;
setCovariance(covariance);
setCovariance(covariance, numObservations);
}
/**

View File

@ -23,6 +23,10 @@ import infodynamics.utils.RandomGenerator;
*/
public abstract class ConditionalMutualInfoCalculatorMultiVariateKraskov
implements ConditionalMutualInfoCalculatorMultiVariate {
// TODO - have this class inhereit from ConditionalMutualInfoMultiVariateCommon
// and remove the overlapping code. This will also solve a lot of the
// "Not implemented yet" exceptions that we're throwing here.
/**
* we compute distances to the kth neighbour in the joint space

View File

@ -8,14 +8,16 @@ import infodynamics.utils.MatrixUtils;
* <p>Compute the Conditional Mutual Info using the Kraskov estimation method,
* as extended by Frenzel and Pompe.</p>
* <p>
* Uses the second algorithm (defined at start of p.3 of the Kraskov paper) -
* Attempts to use the second algorithm (defined at start of p.3 of the Kraskov paper) -
* note that Frenzel and Pompe only extended the technique directly for the
* first algorithm, though here we define it for the second.
* It is unclear exactly how to do this, since we need to account for
* the 1/k factor, which changes in the space of the second
* MI. I've taken a guess, though use of
* It is unclear exactly how to do this - we assume that we only need
* a single 1/k additive factor in the largest joint space (Kraskov seems to do the
* same for the regular MI, noting on p.5 that other correction factors are
* missing, which would go to zero as N -> \infty.
* The implementation here is something of a guess, so use of
* {@link ConditionalMutualInfoCalculatorMultiVariateKraskov1}
* is perhaps recommended instead of this class.</p>
* is perhaps recommended instead of this algorithm 2.</p>
*
* <p>Computes this directly looking at the marginal space for each variable, rather than
* using the multi-info (or integration) in the marginal spaces.
@ -189,23 +191,22 @@ public class ConditionalMutualInfoCalculatorMultiVariateKraskov2
// average:
averageDiGammas += MathsUtils.digamma(n_z) - MathsUtils.digamma(n_xz)
- MathsUtils.digamma(n_yz);
double invN_yz = 1.0 / (double) n_yz;
averageInverseCountInJointYZ += invN_yz;
if (debug) {
// Only tracking this for debugging purposes:
double invN_xz = 1.0/(double) n_xz;
averageInverseCountInJointXZ += invN_xz;
double invN_yz = 1.0 / (double) n_yz;
averageInverseCountInJointYZ += invN_yz;
double localCondMi = MathsUtils.digamma(k) - 1.0 / (double) k +
invN_yz + MathsUtils.digamma(n_z) - MathsUtils.digamma(n_xz)
MathsUtils.digamma(n_z) - MathsUtils.digamma(n_xz)
- MathsUtils.digamma(n_yz);
System.out.printf("t=%d, n_xz=%d, n_yz=%d, n_z=%d, 1/n_yz=%.3f, 1/n_xz=%.3f, local=%.4f\n",
t, n_xz, n_yz, n_z, invN_yz, invN_xz, localCondMi);
}
}
averageDiGammas /= (double) N;
averageInverseCountInJointYZ /= (double) N;
condMi = MathsUtils.digamma(k) - 1.0 / (double) k +
+ averageInverseCountInJointYZ + averageDiGammas;
+ averageDiGammas;
condMiComputed = true;
if (debug) {
@ -213,11 +214,12 @@ public class ConditionalMutualInfoCalculatorMultiVariateKraskov2
avNyz /= (double)N;
avNz /= (double)N;
averageInverseCountInJointXZ /= (double) N;
averageInverseCountInJointYZ /= (double) N;
System.out.printf("<n_xz>=%.3f, <n_yz>=%.3f, <n_z>=%.3f\n",
avNxz, avNyz, avNz);
System.out.printf("Av = digamma(k)=%.3f + <digammas>=%.3f - 1/k=%.3f + <1/n_yz>=%.3f = %.3f (<1/n_xz>=%.3f)\n",
MathsUtils.digamma(k), averageDiGammas, 1.0 / (double) k, averageInverseCountInJointYZ,
condMi, averageInverseCountInJointXZ);
System.out.printf("Av = digamma(k)=%.3f + <digammas>=%.3f - 1/k=%.3f = %.3f (<1/n_yz>=%.3f, <1/n_xz>=%.3f)\n",
MathsUtils.digamma(k), averageDiGammas, 1.0 / (double) k,
condMi, averageInverseCountInJointYZ, averageInverseCountInJointXZ);
}
return condMi;
@ -312,35 +314,35 @@ public class ConditionalMutualInfoCalculatorMultiVariateKraskov2
// average:
averageDiGammas += MathsUtils.digamma(n_z) - MathsUtils.digamma(n_xz)
- MathsUtils.digamma(n_yz);
double invN_yz = 1.0 / (double) n_yz;
averageInverseCountInJointYZ += invN_yz;
if (debug) {
// Only tracking this for debugging purposes:
double invN_xz = 1.0/(double) n_xz;
averageInverseCountInJointXZ += invN_xz;
double invN_yz = 1.0 / (double) n_yz;
averageInverseCountInJointYZ += invN_yz;
double localCondMi = MathsUtils.digamma(k) - 1.0 / (double) k +
invN_yz + MathsUtils.digamma(n_z) - MathsUtils.digamma(n_xz)
MathsUtils.digamma(n_z) - MathsUtils.digamma(n_xz)
- MathsUtils.digamma(n_yz);
System.out.printf("t=%d, n_xz=%d, n_yz=%d, n_z=%d, 1/n_yz=%.3f, 1/n_xz=%.3f, local=%.4f\n",
t, n_xz, n_yz, n_z, invN_yz, invN_xz, localCondMi);
}
}
averageDiGammas /= (double) N;
averageInverseCountInJointYZ /= (double) N;
condMi = MathsUtils.digamma(k) - 1.0 / (double) k +
averageInverseCountInJointYZ + averageDiGammas;
averageDiGammas;
condMiComputed = true;
if (debug) {
avNxz /= (double)N;
avNyz /= (double)N;
avNz /= (double)N;
averageInverseCountInJointYZ /= (double) N;
averageInverseCountInJointXZ /= (double) N;
System.out.printf("<n_xz>=%.3f, <n_yz>=%.3f, <n_z>=%.3f\n",
avNxz, avNyz, avNz);
System.out.printf("Av = digamma(k)=%.3f + <digammas>=%.3f - 1/k=%.3f + <1/n_yz>=%.3f = %.3f (<1/n_xz>=%.3f)\n",
MathsUtils.digamma(k), averageDiGammas, 1.0 / (double) k, averageInverseCountInJointYZ,
condMi, averageInverseCountInJointXZ);
System.out.printf("Av = digamma(k)=%.3f + <digammas>=%.3f - 1/k=%.3f = %.3f (<1/n_yz>=%.3f, <1/n_xz>=%.3f)\n",
MathsUtils.digamma(k), averageDiGammas, 1.0 / (double) k,
condMi, averageInverseCountInJointYZ, averageInverseCountInJointXZ);
}
return condMi;
@ -437,35 +439,35 @@ public class ConditionalMutualInfoCalculatorMultiVariateKraskov2
// average:
averageDiGammas += MathsUtils.digamma(n_z) - MathsUtils.digamma(n_xz)
- MathsUtils.digamma(n_yz);
double invN_yz = 1.0 / (double) n_yz;
averageInverseCountInJointYZ += invN_yz;
if (debug) {
// Only tracking this for debugging purposes:
double invN_xz = 1.0/(double) n_xz;
averageInverseCountInJointXZ += invN_xz;
double invN_yz = 1.0 / (double) n_yz;
averageInverseCountInJointYZ += invN_yz;
double localCondMi = MathsUtils.digamma(k) - 1.0 / (double) k +
invN_yz + MathsUtils.digamma(n_z) - MathsUtils.digamma(n_xz)
MathsUtils.digamma(n_z) - MathsUtils.digamma(n_xz)
- MathsUtils.digamma(n_yz);
System.out.printf("t=%d, n_xz=%d, n_yz=%d, n_z=%d, 1/n_yz=%.3f, 1/n_xz=%.3f, local=%.4f\n",
t, n_xz, n_yz, n_z, invN_yz, invN_xz, localCondMi);
}
}
averageDiGammas /= (double) N;
averageInverseCountInJointYZ /= (double) N;
condMi = MathsUtils.digamma(k) - 1.0 / (double) k +
averageInverseCountInJointYZ + averageDiGammas;
averageDiGammas;
condMiComputed = true;
if (debug) {
avNxz /= (double)N;
avNyz /= (double)N;
avNz /= (double)N;
averageInverseCountInJointYZ /= (double) N;
averageInverseCountInJointXZ /= (double) N;
System.out.printf("<n_xz>=%.3f, <n_yz>=%.3f, <n_z>=%.3f\n",
avNxz, avNyz, avNz);
System.out.printf("Av = digamma(k)=%.3f + <digammas>=%.3f - 1/k=%.3f + <1/n_yz>=%.3f = %.3f (<1/n_xz>=%.3f)\n",
MathsUtils.digamma(k), averageDiGammas, 1.0 / (double) k, averageInverseCountInJointYZ,
condMi, averageInverseCountInJointXZ);
System.out.printf("Av = digamma(k)=%.3f + <digammas>=%.3f - 1/k=%.3f = %.3f (<1/n_yz>=%.3f, <1/n_xz>=%.3f)\n",
MathsUtils.digamma(k), averageDiGammas, 1.0 / (double) k,
condMi, averageInverseCountInJointYZ, averageInverseCountInJointXZ);
}
return condMi;
@ -559,36 +561,35 @@ public class ConditionalMutualInfoCalculatorMultiVariateKraskov2
double digammaNyz = MathsUtils.digamma(n_yz);
double digammaNz = MathsUtils.digamma(n_z);
double invN_yz = 1.0/(double) n_yz;
localCondMi[t] = digammaK - digammaNxz - digammaNyz + digammaNz
- invK + invN_yz;
- invK;
averageDiGammas += digammaNz - digammaNxz - digammaNyz;
averageInverseCountInJointYZ += invN_yz;
if (debug) {
// Only tracking this for debugging purposes:
double invN_yz = 1.0/(double) n_yz;
double invN_xz = 1.0/(double) n_xz;
averageInverseCountInJointYZ += invN_yz;
averageInverseCountInJointXZ += invN_xz;
System.out.printf("t=%d, n_xz=%d, n_yz=%d, n_z=%d, 1/n_yz=%.3f, 1/n_xz=%.3f, local=%.4f\n",
t, n_xz, n_yz, n_z, invN_yz, invN_xz, localCondMi[t]);
}
}
averageDiGammas /= (double) N;
averageInverseCountInJointYZ /= (double) N;
condMi = digammaK + averageDiGammas - invK +
averageInverseCountInJointYZ;
condMi = digammaK + averageDiGammas - invK;
condMiComputed = true;
if (debug) {
avNxz /= (double)N;
avNyz /= (double)N;
avNz /= (double)N;
averageInverseCountInJointYZ /= (double) N;
averageInverseCountInJointXZ /= (double) N;
System.out.printf("<n_xz>=%.3f, <n_yz>=%.3f, <n_z>=%.3f\n",
avNxz, avNyz, avNz);
System.out.printf("Av = digamma(k)=%.3f + <digammas>=%.3f - 1/k=%.3f + <1/n_yz>=%.3f = %.3f (<1/n_xz>=%.3f)\n",
digammaK, averageDiGammas, invK, averageInverseCountInJointYZ,
condMi, averageInverseCountInJointXZ);
System.out.printf("Av = digamma(k)=%.3f + <digammas>=%.3f - 1/k=%.3f = %.3f (<1/n_yz>=%.3f, <1/n_xz>=%.3f)\n",
digammaK, averageDiGammas, invK,
condMi, averageInverseCountInJointYZ, averageInverseCountInJointXZ);
}
return localCondMi;

View File

@ -14,6 +14,9 @@ import infodynamics.utils.RandomGenerator;
* <p>Uses Kraskov method type 2, since type 1 only looks at points with
* distances strictly less than the kth variable, which won't work for one marginal
* being discrete.</p>
* <p>The actual equation which should be used for type 2 with conditional MI is
* not completely clear - this calculator makes an assumption as per {#link ConditionalMutualInfoCalculatorMultiVariateKraskov2}.
* </p>
*
* @see "Estimating mutual information", Kraskov, A., Stogbauer, H., Grassberger, P., Physical Review E 69, (2004) 066138
* @see http://dx.doi.org/10.1103/PhysRevE.69.066138
@ -225,10 +228,11 @@ public class ConditionalMutualInfoCalculatorMultiVariateWithDiscreteKraskov impl
// Count the average number of points within eps_x and eps_y
double averageDiGammas = 0;
double averageInverseCountInJointYZ = 0;
double avNxz = 0;
double avNyz = 0;
double avNz = 0;
@SuppressWarnings("unused") // The following var is only used in debug mode:
double averageInverseCountInJointYZ = 0;
for (int t = 0; t < N; t++) {
// Compute eps_x and eps_z for this time step:
@ -284,20 +288,21 @@ public class ConditionalMutualInfoCalculatorMultiVariateWithDiscreteKraskov impl
// average:
averageDiGammas += MathsUtils.digamma(n_xz) + MathsUtils.digamma(n_yz)
- MathsUtils.digamma(n_z);
averageInverseCountInJointYZ += 1.0 / (double) n_yz;
if (debug) {
averageInverseCountInJointYZ += 1.0 / (double) n_yz;
}
}
averageDiGammas /= (double) N;
averageInverseCountInJointYZ /= (double) N;
if (debug) {
avNxz /= (double)N;
avNyz /= (double)N;
avNz /= (double)N;
averageInverseCountInJointYZ /= (double) N;
System.out.println(String.format("Average n_xz=%.3f, Average n_yz=%.3f, Average n_z=%.3f",
avNxz, avNyz, avNz));
}
condMi = MathsUtils.digamma(k) - 1.0/(double)k +
averageInverseCountInJointYZ - averageDiGammas;
condMi = MathsUtils.digamma(k) - 1.0/(double)k - averageDiGammas;
miComputed = true;
return condMi;
}
@ -373,25 +378,26 @@ public class ConditionalMutualInfoCalculatorMultiVariateWithDiscreteKraskov impl
// average:
averageDiGammas += MathsUtils.digamma(n_xz) + MathsUtils.digamma(n_yz)
- MathsUtils.digamma(n_z);
averageInverseCountInJointYZ += 1.0 / (double) n_yz;
if (debug) {
averageInverseCountInJointYZ += 1.0 / (double) n_yz;
}
}
averageDiGammas /= (double) N;
averageInverseCountInJointYZ /= (double) N;
if (debug) {
avNxz /= (double)N;
avNyz /= (double)N;
avNz /= (double) N;
averageInverseCountInJointYZ /= (double) N;
System.out.printf("Average n_xz=%.3f (-> digam=%.3f %.3f), Average n_yz=%.3f (-> digam=%.3f)",
avNxz, MathsUtils.digamma((int) avNxz), MathsUtils.digamma((int) avNxz - 1), avNyz, MathsUtils.digamma((int) avNyz));
System.out.printf(", Average n_z=%.3f (-> digam=%.3f)\n", avNz, MathsUtils.digamma((int) avNz));
System.out.printf("Independent average num in joint box is %.3f\n", (avNxz * avNyz / (double) N));
System.out.println(String.format("digamma(k)=%.3f - 1/k=%.3f + <1/n_yz>=%.3f - averageDiGammas=%.3f\n",
MathsUtils.digamma(k), 1.0/(double)k, averageInverseCountInJointYZ,
averageDiGammas));
System.out.printf("digamma(k)=%.3f - 1/k=%.3f - averageDiGammas=%.3f (<1/n_yz>=%.3f)\n",
MathsUtils.digamma(k), 1.0/(double)k,
averageDiGammas, averageInverseCountInJointYZ);
}
condMi = MathsUtils.digamma(k) - 1.0/(double)k +
averageInverseCountInJointYZ - averageDiGammas;
condMi = MathsUtils.digamma(k) - 1.0/(double)k - averageDiGammas;
miComputed = true;
return condMi;
}
@ -410,10 +416,11 @@ public class ConditionalMutualInfoCalculatorMultiVariateWithDiscreteKraskov impl
// Count the average number of points within eps_x and eps_y
double averageDiGammas = 0;
double averageInverseCountInJointYZ = 0;
double avNxz = 0;
double avNyz = 0;
double avNz = 0;
@SuppressWarnings("unused") // The following var is only used in debug mode:
double averageInverseCountInJointYZ = 0;
for (int t = 0; t < N; t++) {
// Compute eps_* for this time step:
@ -471,19 +478,21 @@ public class ConditionalMutualInfoCalculatorMultiVariateWithDiscreteKraskov impl
// average:
averageDiGammas += MathsUtils.digamma(n_xz) + MathsUtils.digamma(n_yz)
- MathsUtils.digamma(n_z);
if (debug) {
averageInverseCountInJointYZ += 1.0 / (double) n_yz;
}
}
averageDiGammas /= (double) N;
averageInverseCountInJointYZ /= (double) N;
if (debug) {
avNxz /= (double)N;
avNyz /= (double)N;
avNz /= (double)N;
averageInverseCountInJointYZ /= (double) N;
System.out.printf("Average n_xz=%.3f, Average n_yz=%.3f, Average n_z=%.3f\n",
avNxz, avNyz, avNz);
}
condMi = MathsUtils.digamma(k) - 1.0/(double)k +
averageInverseCountInJointYZ - averageDiGammas;
condMi = MathsUtils.digamma(k) - 1.0/(double)k - averageDiGammas;
miComputed = true;
return condMi;
}

View File

@ -2389,6 +2389,33 @@ public class MatrixUtils {
return c / (double) (x.length - 1); // -1 for sample covariance
}
/**
* <p>Returns the covariance between the two arrays of data, with
* a given lag between the first and second.</p>
* <p>See - <a href="http://mathworld.wolfram.com/Covariance.html">Mathworld</a>
* </p>
*
* @param x time series 1
* @param y time series 2
* @param delay delay >= 0 to compute the covariance across (from first to second time series)
* @return the covariance
*/
public static double covariance(double[] x, double[] y, int delay) {
double meanX = 0, meanY = 0;
// No error checking if y is same length as x
for (int n = 0; n < x.length - delay; n++) {
meanX += x[n];
meanY += y[n + delay];
}
meanX /= (double) (x.length - delay);
meanY /= (double) (x.length - delay);
double c = 0;
for (int t = 0; t < x.length - delay; t++) {
c += (x[t] - meanX)*(y[t + delay]-meanY);
}
return c / (double) (x.length - delay - 1); // -1 for sample covariance
}
/**
* <p>Returns the covariance between the first two columns of data.</p>
*
@ -3093,6 +3120,7 @@ public class MatrixUtils {
* @see {@link http://mathworld.wolfram.com/CholeskyDecomposition.html}
* @see {@link http://en.wikipedia.org/wiki/Positive-definite_matrix}
* @see {@link http://math.nist.gov/javanumerics/jama/}
* @see {@link http://www2.gsu.edu/~mkteer/npdmatri.html}
*/
public static double[][] CholeskyDecomposition(double[][] A) throws Exception {
int n = A.length;
@ -3119,7 +3147,11 @@ public class MatrixUtils {
d = A[j][j] - d;
// Check the positive definite condition:
if (d <= 0.0) {
throw new Exception("CholeskyDecomposition is only performed on positive-definite matrices");
// Throw an error with some suggestions. The last suggestion is from my observations
// from a simple test with Matlab - I should find a reference for this ...
throw new Exception("CholeskyDecomposition is only performed on positive-definite matrices. " +
"Some reasons for non-positive-definite matrix are listed at http://www2.gsu.edu/~mkteer/npdmatri.html - " +
"note: a correlation matrix is non-positive-definite if you have more variables than observations");
}
L[j][j] = Math.sqrt(d);
// Set the upper triangular part to all zeros:

View File

@ -25,6 +25,7 @@ public class OctaveFileReader {
static final String GLOBAL_SCALAR_HEADER = "# type: scalar";
static final String MATRIX_HEADER = "# type: matrix";
static final String GLOBAL_MATRIX_HEADER = "# type: global matrix";
static final String BOOL_MATRIX_HEADER = "# type: bool matrix";
static final String OCTAVE_DELIMITER = "[ \t]";
public OctaveFileReader(String octaveFilename) throws FileNotFoundException {
@ -123,7 +124,8 @@ public class OctaveFileReader {
// We have the header line for this stored variable
// Make sure the next line indicates a matrix
line = br.readLine();
if (!line.equals(MATRIX_HEADER) && !line.equals(GLOBAL_MATRIX_HEADER)) {
if (!line.equals(MATRIX_HEADER) && !line.equals(GLOBAL_MATRIX_HEADER)
&& !line.equals(BOOL_MATRIX_HEADER)) {
// The variable is not a matrix - it is not compatible with the
// int [] type
throw new Exception("Stored Octave variable " + name + " is not of a type compatible with int[] - not a matrix");
@ -180,7 +182,8 @@ public class OctaveFileReader {
// We have the header line for this stored variable
// Make sure the next line indicates a matrix
line = br.readLine();
if (!line.equals(MATRIX_HEADER) && !line.equals(GLOBAL_MATRIX_HEADER)) {
if (!line.equals(MATRIX_HEADER) && !line.equals(GLOBAL_MATRIX_HEADER)
&& !line.equals(BOOL_MATRIX_HEADER)) {
// The variable is not a matrix - it is not compatible with the
// int [] type
throw new Exception("Stored Octave variable " + name + " is not of a type compatible with long[] - not a matrix");
@ -294,7 +297,8 @@ public class OctaveFileReader {
// We have the header line for this stored variable
// Make sure the next line indicates a matirx
line = br.readLine();
if (!line.equals(MATRIX_HEADER) && !line.equals(GLOBAL_MATRIX_HEADER)) {
if (!line.equals(MATRIX_HEADER) && !line.equals(GLOBAL_MATRIX_HEADER)
&& !line.equals(BOOL_MATRIX_HEADER)) {
// The variable is not a matrix - it is not compatible with the
// int [][] type
throw new Exception("Stored Octave variable " + name + " is not of a type compatible with int[][]");