Adding/implementing interfaces for continuous CMI estimators to allow all combinations of univariate/multivariate arrays to be passed for var1/var2/conditional

This commit is contained in:
Joseph Lizier 2023-10-27 10:04:25 +11:00
parent 7d8b501127
commit 2130985c34
4 changed files with 339 additions and 31 deletions

View File

@ -129,17 +129,8 @@ public interface ConditionalMutualInfoCalculatorMultiVariate
double[][] cond) throws Exception;
/**
* Sets a single series from which to compute the PDF.
* Cannot be called in conjunction with
* {@link #startAddObservations()} / {@link #addObservations(double[][], double[][], double[][])} or
* {@link #addObservations(double[][], double[][], double[][], int, int)} /
* {@link #finaliseAddObservations()}.</p>
*
* <p>The supplied series may be (multivariate) time-series or
* simply a set of separate observations without a time interpretation.
*
* <p>This method can only be used where dimensions of all
* variables have been set to 1.</p>
* As per {@link #setObservations(double[][], double[][], double[][])}
* but where dimensions of all variables have been set to 1
*
* @param var1 univariate observations for variable 1
* @param var2 univariate observations for variable 2
@ -151,6 +142,90 @@ public interface ConditionalMutualInfoCalculatorMultiVariate
public void setObservations(double[] var1, double[] var2,
double[] cond) throws Exception;
/**
* As per {@link #setObservations(double[][], double[][], double[][])}
* but where dimensions of var2 and cond are 1
*
* @param var1 observations for variable 1
* @param var2 univariate observations for variable 2
* Length must match <code>var1</code>, and their indices must correspond.
* @param cond univariate observations for the conditional
* Length must match <code>var1</code>, and their indices must correspond.
* @throws Exception
*/
public void setObservations(double[][] var1, double[] var2,
double[] cond) throws Exception;
/**
* As per {@link #setObservations(double[][], double[][], double[][])}
* but where dimensions of var1 and cond are 1
*
* @param var1 univariate observations for variable 1
* @param var2 observations for variable 2
* Length must match <code>var1</code>, and their indices must correspond.
* @param cond univariate observations for the conditional
* Length must match <code>var1</code>, and their indices must correspond.
* @throws Exception
*/
public void setObservations(double[] var1, double[][] var2,
double[] cond) throws Exception;
/**
* As per {@link #setObservations(double[][], double[][], double[][])}
* but where dimensions of var1 and var2 are 1
*
* @param var1 univariate observations for variable 1
* @param var2 univariate observations for variable 2
* Length must match <code>var1</code>, and their indices must correspond.
* @param cond observations for the conditional
* Length must match <code>var1</code>, and their indices must correspond.
* @throws Exception
*/
public void setObservations(double[] var1, double[] var2,
double[][] cond) throws Exception;
/**
* As per {@link #setObservations(double[][], double[][], double[][])}
* but where dimension of cond is 1
*
* @param var1 observations for variable 1
* @param var2 observations for variable 2
* Length must match <code>var1</code>, and their indices must correspond.
* @param cond univariate observations for the conditional
* Length must match <code>var1</code>, and their indices must correspond.
* @throws Exception
*/
public void setObservations(double[][] var1, double[][] var2,
double[] cond) throws Exception;
/**
* As per {@link #setObservations(double[][], double[][], double[][])}
* but where dimension of var2 is 1
*
* @param var1 observations for variable 1
* @param var2 univariate observations for variable 2
* Length must match <code>var1</code>, and their indices must correspond.
* @param cond observations for the conditional
* Length must match <code>var1</code>, and their indices must correspond.
* @throws Exception
*/
public void setObservations(double[][] var1, double[] var2,
double[][] cond) throws Exception;
/**
* As per {@link #setObservations(double[][], double[][], double[][])}
* but where dimension of var1 is 1
*
* @param var1 univariate observations for variable 1
* @param var2 observations for variable 2
* Length must match <code>var1</code>, and their indices must correspond.
* @param cond observations for the conditional
* Length must match <code>var1</code>, and their indices must correspond.
* @throws Exception
*/
public void setObservations(double[] var1, double[][] var2,
double[][] cond) throws Exception;
/**
* Sets a single series from which to compute the PDF,
* where all the various observations are valid.
@ -248,18 +323,8 @@ public interface ConditionalMutualInfoCalculatorMultiVariate
double[][] cond) throws Exception;
/**
* <p>Adds a new set of observations to update the PDFs with - is
* intended to be called multiple times.
* Must be called after {@link #startAddObservations()}; call
* {@link #finaliseAddObservations()} once all observations have
* been supplied.</p>
*
* <p>Note that the arrays must not be over-written by the user
* until after finaliseAddObservations() has been called
* (they are not copied by this method necessarily, but the method
* may simply hold a pointer to them).</p>
*
* <p>This method can only be used where dimensions of all
* <p>As per {@link #addObservations(double[][], double[][], double[][])}
* but can only be used where dimensions of all
* variables have been set to 1.</p>
*
* @param var1 univariate observations for variable 1
@ -272,6 +337,96 @@ public interface ConditionalMutualInfoCalculatorMultiVariate
public void addObservations(double[] var1, double[] var2,
double[] cond) throws Exception;
/**
* <p>As per {@link #addObservations(double[][], double[][], double[][])}
* but can only be used where dimensions of
* var2 and cond have been set to 1.</p>
*
* @param var1 observations for variable 1
* @param var2 univariate observations for variable 2
* Length must match <code>var1</code>, and their indices must correspond.
* @param cond univariate observations for the conditional
* Length must match <code>var1</code>, and their indices must correspond.
* @throws Exception
*/
public void addObservations(double[][] var1, double[] var2,
double[] cond) throws Exception;
/**
* <p>As per {@link #addObservations(double[][], double[][], double[][])}
* but can only be used where dimensions of
* var1 and cond have been set to 1.</p>
*
* @param var1 univariate observations for variable 1
* @param var2 observations for variable 2
* Length must match <code>var1</code>, and their indices must correspond.
* @param cond univariate observations for the conditional
* Length must match <code>var1</code>, and their indices must correspond.
* @throws Exception
*/
public void addObservations(double[] var1, double[][] var2,
double[] cond) throws Exception;
/**
* <p>As per {@link #addObservations(double[][], double[][], double[][])}
* but can only be used where dimensions of
* var1 and var2 have been set to 1.</p>
*
* @param var1 univariate observations for variable 1
* @param var2 univariate observations for variable 2
* Length must match <code>var1</code>, and their indices must correspond.
* @param cond observations for the conditional
* Length must match <code>var1</code>, and their indices must correspond.
* @throws Exception
*/
public void addObservations(double[] var1, double[] var2,
double[][] cond) throws Exception;
/**
* <p>As per {@link #addObservations(double[][], double[][], double[][])}
* but can only be used where dimensions of
* var1 have been set to 1.</p>
*
* @param var1 univariate observations for variable 1
* @param var2 observations for variable 2
* Length must match <code>var1</code>, and their indices must correspond.
* @param cond observations for the conditional
* Length must match <code>var1</code>, and their indices must correspond.
* @throws Exception
*/
public void addObservations(double[] var1, double[][] var2,
double[][] cond) throws Exception;
/**
* <p>As per {@link #addObservations(double[][], double[][], double[][])}
* but can only be used where dimensions of
* var2 have been set to 1.</p>
*
* @param var1 observations for variable 1
* @param var2 univariate observations for variable 2
* Length must match <code>var1</code>, and their indices must correspond.
* @param cond observations for the conditional
* Length must match <code>var1</code>, and their indices must correspond.
* @throws Exception
*/
public void addObservations(double[][] var1, double[] var2,
double[][] cond) throws Exception;
/**
* <p>As per {@link #addObservations(double[][], double[][], double[][])}
* but can only be used where dimensions of
* cond have been set to 1.</p>
*
* @param var1 observations for variable 1
* @param var2 observations for variable 2
* Length must match <code>var1</code>, and their indices must correspond.
* @param cond univariate observations for the conditional
* Length must match <code>var1</code>, and their indices must correspond.
* @throws Exception
*/
public void addObservations(double[][] var1, double[][] var2,
double[] cond) throws Exception;
/**
* <p>Adds a new sub-series of observations to update the PDFs with - is
* intended to be called multiple times.

View File

@ -287,8 +287,7 @@ public abstract class ConditionalMutualInfoMultiVariateCommon implements
}
@Override
public void setObservations(double[][] var1, double[][] var2,
double[][] cond) throws Exception {
public void setObservations(double[][] var1, double[][] var2, double[][] cond) throws Exception {
startAddObservations();
addObservations(var1, var2, cond);
finaliseAddObservations();
@ -297,7 +296,8 @@ public abstract class ConditionalMutualInfoMultiVariateCommon implements
/**
* A non-overloaded method signature for setObservations with 2D arguments, as there have been
* some problems calling overloaded versions of setObservations from jpype.
* some problems calling overloaded versions of setObservations from python jpype.
* Resolved if one follows the AutoAnalyser generated code, but left for back compatibility.
*
* @param var1
* @param var2
@ -309,8 +309,55 @@ public abstract class ConditionalMutualInfoMultiVariateCommon implements
}
@Override
public void setObservations(double[] var1, double[] var2,
double[] cond) throws Exception {
public void setObservations(double[] var1, double[] var2, double[] cond) throws Exception {
startAddObservations();
addObservations(var1, var2, cond);
finaliseAddObservations();
addedMoreThanOneObservationSet = false;
}
@Override
public void setObservations(double[][] var1, double[] var2, double[] cond) throws Exception {
startAddObservations();
addObservations(var1, var2, cond);
finaliseAddObservations();
addedMoreThanOneObservationSet = false;
}
@Override
public void setObservations(double[] var1, double[][] var2, double[] cond) throws Exception {
startAddObservations();
addObservations(var1, var2, cond);
finaliseAddObservations();
addedMoreThanOneObservationSet = false;
}
@Override
public void setObservations(double[] var1, double[] var2, double[][] cond) throws Exception {
startAddObservations();
addObservations(var1, var2, cond);
finaliseAddObservations();
addedMoreThanOneObservationSet = false;
}
@Override
public void setObservations(double[] var1, double[][] var2, double[][] cond) throws Exception {
startAddObservations();
addObservations(var1, var2, cond);
finaliseAddObservations();
addedMoreThanOneObservationSet = false;
}
@Override
public void setObservations(double[][] var1, double[] var2, double[][] cond) throws Exception {
startAddObservations();
addObservations(var1, var2, cond);
finaliseAddObservations();
addedMoreThanOneObservationSet = false;
}
@Override
public void setObservations(double[][] var1, double[][] var2, double[] cond) throws Exception {
startAddObservations();
addObservations(var1, var2, cond);
finaliseAddObservations();
@ -319,7 +366,8 @@ public abstract class ConditionalMutualInfoMultiVariateCommon implements
/**
* A non-overloaded method signature for setObservations with 1D arguments, as there have been
* some problems calling overloaded versions of setObservations from jpype.
* some problems calling overloaded versions of setObservations from python jpype.
* Resolved if one follows the AutoAnalyser generated code, but left for back compatibility.
*
* @param var1
* @param var2
@ -428,6 +476,7 @@ public abstract class ConditionalMutualInfoMultiVariateCommon implements
}
double[][] reshapedConditional = null;
if (dimensionsCond == 1) {
// This won't execute if dimensionsCond == 0
reshapedConditional = MatrixUtils.reshape(cond, cond.length, 1);
}
addObservations(MatrixUtils.reshape(var1, var1.length, 1),
@ -436,6 +485,110 @@ public abstract class ConditionalMutualInfoMultiVariateCommon implements
}
@Override
public void addObservations(double[][] var1, double[] var2,
double[] cond) throws Exception {
if ((dimensionsVar2 != 1) ||
((dimensionsCond != 1) && (dimensionsCond != 0))) {
throw new Exception("The number of dimensions for variables var2 and cond (having been initialised to " +
dimensionsVar2 + " & " +
dimensionsCond + ") can only be 1 (or 0 for conditional) when " +
"the addObservations(double[][],double[],double[]) and " +
"setObservations(double[][],double[],double[]) methods are called");
}
double[][] reshapedConditional = null;
if (dimensionsCond == 1) {
// This won't execute if dimensionsCond == 0
reshapedConditional = MatrixUtils.reshape(cond, cond.length, 1);
}
addObservations(var1,
MatrixUtils.reshape(var2, var2.length, 1),
reshapedConditional);
}
@Override
public void addObservations(double[] var1, double[][] var2,
double[] cond) throws Exception {
if ((dimensionsVar1 != 1) ||
((dimensionsCond != 1) && (dimensionsCond != 0))) {
throw new Exception("The number of dimensions for variables var1 and cond (having been initialised to " +
dimensionsVar1 + " & " +
dimensionsCond + ") can only be 1 (or 0 for conditional) when " +
"the addObservations(double[],double[][],double[]) and " +
"setObservations(double[],double[][],double[]) methods are called");
}
double[][] reshapedConditional = null;
if (dimensionsCond == 1) {
// This won't execute if dimensionsCond == 0
reshapedConditional = MatrixUtils.reshape(cond, cond.length, 1);
}
addObservations(MatrixUtils.reshape(var1, var1.length, 1),
var2,
reshapedConditional);
}
@Override
public void addObservations(double[] var1, double[] var2,
double[][] cond) throws Exception {
if ((dimensionsVar1 != 1) || (dimensionsVar2 != 1)) {
throw new Exception("The number of dimensions for variables var1 and var2 (having been initialised to " +
dimensionsVar1 + " & " +
dimensionsVar2 + ") can only be 1 when " +
"the addObservations(double[],double[],double[][]) and " +
"setObservations(double[],double[],double[][]) methods are called");
}
addObservations(MatrixUtils.reshape(var1, var1.length, 1),
MatrixUtils.reshape(var2, var2.length, 1),
cond);
}
@Override
public void addObservations(double[] var1, double[][] var2,
double[][] cond) throws Exception {
if (dimensionsVar1 != 1) {
throw new Exception("The number of dimensions for variable var1 (having been initialised to " +
dimensionsVar1 + ") can only be 1 when " +
"the addObservations(double[],double[][],double[][]) and " +
"setObservations(double[],double[][],double[][]) methods are called");
}
addObservations(MatrixUtils.reshape(var1, var1.length, 1),
var2,
cond);
}
@Override
public void addObservations(double[][] var1, double[] var2,
double[][] cond) throws Exception {
if (dimensionsVar2 != 1) {
throw new Exception("The number of dimensions for variable var2 (having been initialised to " +
dimensionsVar2 + ") can only be 1 when " +
"the addObservations(double[][],double[],double[][]) and " +
"setObservations(double[][],double[],double[][]) methods are called");
}
addObservations(var1,
MatrixUtils.reshape(var2, var2.length, 1),
cond);
}
@Override
public void addObservations(double[][] var1, double[][] var2,
double[] cond) throws Exception {
if ((dimensionsCond != 1) && (dimensionsCond != 0)) {
throw new Exception("The number of dimensions for variable cond (having been initialised to " +
dimensionsCond + ") can only be 1 or 0 when " +
"the addObservations(double[][],double[][],double[]) and " +
"setObservations(double[][],double[][],double[]) methods are called");
}
double[][] reshapedConditional = null;
if (dimensionsCond == 1) {
// This won't execute if dimensionsCond == 0
reshapedConditional = MatrixUtils.reshape(cond, cond.length, 1);
}
addObservations(var1,
var2,
reshapedConditional);
}
/**
* A non-overloaded method signature for addObservations with 1D arguments, as there have been
* some problems calling overloaded versions of setObservations from jpype.

View File

@ -176,7 +176,7 @@ public class ConditionalMutualInfoMultiVariateTester extends
ConditionalMutualInfoCalculatorMultiVariateGaussian condMiCalc =
new ConditionalMutualInfoCalculatorMultiVariateGaussian();
condMiCalc.initialise(1, 1, 0);
condMiCalc.setObservations(source, dest, null);
condMiCalc.setObservations(source, dest, (double[][]) null);
double condMi = condMiCalc.computeAverageLocalOfObservations();
assertEquals(mi, condMi, 0.000001);

View File

@ -700,7 +700,7 @@ public class ConditionalMutualInfoMultiVariateTester
// EuclideanUtils.NORM_MAX_NORM_STRING);
condMiCalc.setProperty(MutualInfoCalculatorMultiVariateKraskov.PROP_ADD_NOISE, "0"); // Need consistency for unit tests
condMiCalc.initialise(var1[0].length, var2[0].length, 0);
condMiCalc.setObservations(var1, var2, null);
condMiCalc.setObservations(var1, var2, (double[][]) null);
// condMiCalc.setDebug(true);
double mi = condMiCalc.computeAverageLocalOfObservations();
// condMiCalc.setDebug(false);