Making Kraskov MI and higher order calculators use MAX_NORM in the marginal spaces by default (previously this had to be supplied via a property - it was the standard choice made, but was not the default). This aligns with the default specified in the Kraskov paper.

This commit is contained in:
joseph.lizier 2012-12-20 10:38:03 +00:00
parent 87f7be56a5
commit 617880f9f5
10 changed files with 123 additions and 41 deletions

View File

@ -33,6 +33,7 @@ public abstract class ConditionalMutualInfoCalculatorMultiVariateKraskov {
protected double condMi;
protected boolean condMiComputed;
protected EuclideanUtils normCalculator;
// Storage for the norms from each observation to each other one
protected double[][] xNorms;
protected double[][] yNorms;
@ -50,6 +51,7 @@ public abstract class ConditionalMutualInfoCalculatorMultiVariateKraskov {
public ConditionalMutualInfoCalculatorMultiVariateKraskov() {
super();
k = 1; // by default
normCalculator = new EuclideanUtils(EuclideanUtils.NORM_MAX_NORM);
}
public void initialise(int dimensions1, int dimensions2, int dimensionsCond) {
@ -63,11 +65,27 @@ public abstract class ConditionalMutualInfoCalculatorMultiVariateKraskov {
// No need to keep the dimensions here
}
/**
* Sets properties for the calculator.
* Valid properties include:
* <ul>
* <li>{@link #PROP_K} - number of neighbouring points in joint kernel space</li>
* <li>{@link #PROP_NORM_TYPE}</li> - normalization type to apply to
* working out the norms between the points in each marginal space.
* Options are defined by {@link EuclideanUtils#setNormToUse(String)} -
* default is {@link EuclideanUtils#NORM_MAX_NORM}.
* <li>{@link #PROP_NORMALISE} - whether to normalise the individual
* variables (true by default)</li>
* </ul>
*
* @param propertyName name of the property to set
* @param propertyValue value to set on that property
*/
public void setProperty(String propertyName, String propertyValue) {
if (propertyName.equalsIgnoreCase(PROP_K)) {
k = Integer.parseInt(propertyValue);
} else if (propertyName.equalsIgnoreCase(PROP_NORM_TYPE)) {
EuclideanUtils.setNormToUse(propertyValue);
normCalculator.setNormToUse(propertyValue);
} else if (propertyName.equalsIgnoreCase(PROP_NORMALISE)) {
normalise = Boolean.parseBoolean(propertyValue);
}
@ -149,7 +167,7 @@ public abstract class ConditionalMutualInfoCalculatorMultiVariateKraskov {
zNorms = new double[N][N];
for (int t = 0; t < N; t++) {
// Compute the norms from t to all other time points
double[][] xyzNormsForT = EuclideanUtils.computeNorms(data1,
double[][] xyzNormsForT = normCalculator.computeNorms(data1,
data2, dataCond, t);
for (int t2 = 0; t2 < N; t2++) {
xNorms[t][t2] = xyzNormsForT[t2][0];

View File

@ -1,6 +1,5 @@
package infodynamics.measures.continuous.kraskov;
import infodynamics.utils.EuclideanUtils;
import infodynamics.utils.MathsUtils;
import infodynamics.utils.MatrixUtils;
@ -164,7 +163,7 @@ public class ConditionalMutualInfoCalculatorMultiVariateKraskov1
// Compute eps for this time step:
// First get x and y norms to all neighbours
// (note that norm of point t to itself will be set to infinity).
double[][] xyzNorms = EuclideanUtils.computeNorms(data1, data2, dataCond, t);
double[][] xyzNorms = normCalculator.computeNorms(data1, data2, dataCond, t);
double[] jointNorm = new double[N];
for (int t2 = 0; t2 < N; t2++) {
jointNorm[t2] = Math.max(xyzNorms[t2][0], Math.max(xyzNorms[t2][1], xyzNorms[t2][2]));
@ -239,7 +238,7 @@ public class ConditionalMutualInfoCalculatorMultiVariateKraskov1
// Compute eps for this time step:
// First get x and y and z norms to all neighbours
// (note that norm of point t to itself will be set to infinity.
double[][] xyzNorms = EuclideanUtils.computeNorms(data1, data2, dataCond, t);
double[][] xyzNorms = normCalculator.computeNorms(data1, data2, dataCond, t);
double[] jointNorm = new double[N];
for (int t2 = 0; t2 < N; t2++) {
jointNorm[t2] = Math.max(xyzNorms[t2][0], Math.max(xyzNorms[t2][1], xyzNorms[t2][2]));

View File

@ -1,6 +1,5 @@
package infodynamics.measures.continuous.kraskov;
import infodynamics.utils.EuclideanUtils;
import infodynamics.utils.FirstIndexComparatorDouble;
import infodynamics.utils.MathsUtils;
import infodynamics.utils.MatrixUtils;
@ -297,7 +296,7 @@ public class ConditionalMutualInfoCalculatorMultiVariateKraskov2
// Compute eps_x and eps_y and eps_z for this time step:
// First get x and y and z norms to all neighbours
// (note that norm of point t to itself will be set to infinity).
double[][] xyzNorms = EuclideanUtils.computeNorms(data1, data2, dataCond, t);
double[][] xyzNorms = normCalculator.computeNorms(data1, data2, dataCond, t);
double[][] jointNorm = new double[N][2];
for (int t2 = 0; t2 < N; t2++) {
jointNorm[t2][JOINT_NORM_VAL_COLUMN] = Math.max(xyzNorms[t2][0],
@ -400,7 +399,7 @@ public class ConditionalMutualInfoCalculatorMultiVariateKraskov2
// Compute eps_x and eps_y and eps_z for this time step:
// First get x and y and z norms to all neighbours
// (note that norm of point t to itself will be set to infinity).
double[][] xyzNorms = EuclideanUtils.computeNorms(data1, data2, dataCond, t);
double[][] xyzNorms = normCalculator.computeNorms(data1, data2, dataCond, t);
double[][] jointNorm = new double[N][2];
for (int t2 = 0; t2 < N; t2++) {
jointNorm[t2][JOINT_NORM_VAL_COLUMN] = Math.max(xyzNorms[t2][0],

View File

@ -39,6 +39,7 @@ public class ConditionalMutualInfoCalculatorMultiVariateWithDiscreteKraskov impl
protected double condMi;
protected boolean miComputed;
protected EuclideanUtils normCalculator;
// Storage for the norms from each observation to each other one
protected double[][] xNorms;
protected double[][] zNorms;
@ -56,6 +57,7 @@ public class ConditionalMutualInfoCalculatorMultiVariateWithDiscreteKraskov impl
public ConditionalMutualInfoCalculatorMultiVariateWithDiscreteKraskov() {
super();
k = 1; // by default
normCalculator = new EuclideanUtils(EuclideanUtils.NORM_MAX_NORM);
}
/**
@ -77,15 +79,26 @@ public class ConditionalMutualInfoCalculatorMultiVariateWithDiscreteKraskov impl
}
/**
* Sets properties for the calculator.
* Valid properties include:
* <ul>
* <li>{@link #PROP_K} - number of neighbouring points in joint kernel space</li>
* <li>{@link #PROP_NORM_TYPE}</li> - normalization type to apply to
* working out the norms between the points in each marginal space.
* Options are defined by {@link EuclideanUtils#setNormToUse(String)} -
* default is {@link EuclideanUtils#NORM_MAX_NORM}.
* <li>{@link #PROP_NORMALISE} - whether to normalise the individual
* variables (true by default)</li>
* </ul>
*
* @param propertyName name of the property to set
* @param propertyValue value to set on that property
* @param propertyName
* @param propertyValue
*/
public void setProperty(String propertyName, String propertyValue) {
if (propertyName.equalsIgnoreCase(PROP_K)) {
k = Integer.parseInt(propertyValue);
} else if (propertyName.equalsIgnoreCase(PROP_NORM_TYPE)) {
EuclideanUtils.setNormToUse(propertyValue);
normCalculator.setNormToUse(propertyValue);
} else if (propertyName.equalsIgnoreCase(PROP_NORMALISE)) {
normalise = Boolean.parseBoolean(propertyValue);
}
@ -172,8 +185,8 @@ public class ConditionalMutualInfoCalculatorMultiVariateWithDiscreteKraskov impl
continue;
}
// Compute norm in the continuous space
xNorms[t][t2] = EuclideanUtils.norm(continuousDataX[t], continuousDataX[t2]);
zNorms[t][t2] = EuclideanUtils.norm(conditionedDataZ[t], conditionedDataZ[t2]);
xNorms[t][t2] = normCalculator.norm(continuousDataX[t], continuousDataX[t2]);
zNorms[t][t2] = normCalculator.norm(conditionedDataZ[t], conditionedDataZ[t2]);
xzNorms[t][t2] = Math.max(xNorms[t][t2], zNorms[t][t2]);
}
}
@ -406,7 +419,7 @@ public class ConditionalMutualInfoCalculatorMultiVariateWithDiscreteKraskov impl
// Compute eps_* for this time step:
// First get xz norms to all neighbours
// (note that norm of point t to itself will be set to infinity).
double[][] xzNorms = EuclideanUtils.computeNorms(continuousDataX, conditionedDataZ, t);
double[][] xzNorms = normCalculator.computeNorms(continuousDataX, conditionedDataZ, t);
double[][] jointNorm = new double[N][2];
for (int t2 = 0; t2 < N; t2++) {
jointNorm[t2][0] = Math.max(xzNorms[t2][0],

View File

@ -32,6 +32,7 @@ public abstract class MultiInfoCalculatorKraskov implements
protected int N; // number of observations
protected int V; // number of variables
protected EuclideanUtils normCalculator;
// Storage for the norms for each marginal variable from each observation to each other one
protected double[][][] norms;
// Keep the norms each time (making reordering very quick)
@ -46,6 +47,7 @@ public abstract class MultiInfoCalculatorKraskov implements
public MultiInfoCalculatorKraskov() {
super();
k = 1; // by default
normCalculator = new EuclideanUtils(EuclideanUtils.NORM_MAX_NORM);
}
public void initialise(int dimensions) {
@ -56,11 +58,26 @@ public abstract class MultiInfoCalculatorKraskov implements
data = null;
}
/**
* Sets properties for the calculator.
* Valid properties include:
* <ul>
* <li>{@link #PROP_K} - number of neighbouring points in joint kernel space</li>
* <li>{@link #PROP_NORM_TYPE}</li> - normalization type to apply to
* working out the norms between the points in each marginal space.
* Options are defined by {@link EuclideanUtils#setNormToUse(String)} -
* default is {@link EuclideanUtils#NORM_MAX_NORM}.
* <li>{@link #PROP_TRY_TO_KEEP_ALL_PAIRS_NORM})</li>
* </ul>
*
* @param propertyName
* @param propertyValue
*/
public void setProperty(String propertyName, String propertyValue) {
if (propertyName.equalsIgnoreCase(PROP_K)) {
k = Integer.parseInt(propertyValue);
} else if (propertyName.equalsIgnoreCase(PROP_NORM_TYPE)) {
EuclideanUtils.setNormToUse(propertyValue);
normCalculator.setNormToUse(propertyValue);
} else if (propertyName.equalsIgnoreCase(PROP_TRY_TO_KEEP_ALL_PAIRS_NORM)) {
tryKeepAllPairsNorms = Boolean.parseBoolean(propertyValue);
}

View File

@ -29,6 +29,7 @@ public abstract class MutualInfoCalculatorMultiVariateKraskov implements
protected double mi;
protected boolean miComputed;
protected EuclideanUtils normCalculator;
// Storage for the norms from each observation to each other one
protected double[][] xNorms;
protected double[][] yNorms;
@ -46,6 +47,7 @@ public abstract class MutualInfoCalculatorMultiVariateKraskov implements
public MutualInfoCalculatorMultiVariateKraskov() {
super();
k = 1; // by default
normCalculator = new EuclideanUtils(EuclideanUtils.NORM_MAX_NORM);
}
public void initialise(int dimensions1, int dimensions2) {
@ -63,8 +65,12 @@ public abstract class MutualInfoCalculatorMultiVariateKraskov implements
* Valid properties include:
* <ul>
* <li>{@link #PROP_K} - number of neighbouring points in joint kernel space</li>
* <li>{@link #PROP_NORM_TYPE}</li>
* <li>{@link #PROP_NORMALISE}</li>
* <li>{@link #PROP_NORM_TYPE}</li> - normalization type to apply to
* working out the norms between the points in each marginal space.
* Options are defined by {@link EuclideanUtils#setNormToUse(String)} -
* default is {@link EuclideanUtils#NORM_MAX_NORM}.
* <li>{@link #PROP_NORMALISE} - whether to normalise the individual
* variables (true by default)</li>
* <li>{@link MutualInfoCalculatorMultiVariate#PROP_TIME_DIFF}</li>
* </ul>
*
@ -75,7 +81,7 @@ public abstract class MutualInfoCalculatorMultiVariateKraskov implements
if (propertyName.equalsIgnoreCase(PROP_K)) {
k = Integer.parseInt(propertyValue);
} else if (propertyName.equalsIgnoreCase(PROP_NORM_TYPE)) {
EuclideanUtils.setNormToUse(propertyValue);
normCalculator.setNormToUse(propertyValue);
} else if (propertyName.equalsIgnoreCase(PROP_NORMALISE)) {
normalise = Boolean.parseBoolean(propertyValue);
} else if (propertyName.equalsIgnoreCase(PROP_TIME_DIFF)) {
@ -154,7 +160,7 @@ public abstract class MutualInfoCalculatorMultiVariateKraskov implements
yNorms = new double[N][N];
for (int t = 0; t < N; t++) {
// Compute the norms from t to all other time points
double[][] xyNormsForT = EuclideanUtils.computeNorms(data1, data2, t);
double[][] xyNormsForT = normCalculator.computeNorms(data1, data2, t);
for (int t2 = 0; t2 < N; t2++) {
xNorms[t][t2] = xyNormsForT[t2][0];
yNorms[t][t2] = xyNormsForT[t2][1];

View File

@ -1,6 +1,5 @@
package infodynamics.measures.continuous.kraskov;
import infodynamics.utils.EuclideanUtils;
import infodynamics.utils.MathsUtils;
import infodynamics.utils.MatrixUtils;
@ -146,7 +145,7 @@ public class MutualInfoCalculatorMultiVariateKraskov1
// Compute eps for this time step:
// First get x and y norms to all neighbours
// (note that norm of point t to itself will be set to infinity).
double[][] xyNorms = EuclideanUtils.computeNorms(data1, data2, t);
double[][] xyNorms = normCalculator.computeNorms(data1, data2, t);
double[] jointNorm = new double[N];
for (int t2 = 0; t2 < N; t2++) {
jointNorm[t2] = Math.max(xyNorms[t2][0], xyNorms[t2][1]);
@ -213,7 +212,7 @@ public class MutualInfoCalculatorMultiVariateKraskov1
// Compute eps for this time step:
// First get x and y norms to all neighbours
// (note that norm of point t to itself will be set to infinity.
double[][] xyNorms = EuclideanUtils.computeNorms(data1, data2, t);
double[][] xyNorms = normCalculator.computeNorms(data1, data2, t);
double[] jointNorm = new double[N];
for (int t2 = 0; t2 < N; t2++) {
jointNorm[t2] = Math.max(xyNorms[t2][0], xyNorms[t2][1]);

View File

@ -1,6 +1,5 @@
package infodynamics.measures.continuous.kraskov;
import infodynamics.utils.EuclideanUtils;
import infodynamics.utils.FirstIndexComparatorDouble;
import infodynamics.utils.MathsUtils;
import infodynamics.utils.MatrixUtils;
@ -246,7 +245,7 @@ public class MutualInfoCalculatorMultiVariateKraskov2
// Compute eps_x and eps_y for this time step:
// First get x and y norms to all neighbours
// (note that norm of point t to itself will be set to infinity).
double[][] xyNorms = EuclideanUtils.computeNorms(data1, data2, t);
double[][] xyNorms = normCalculator.computeNorms(data1, data2, t);
double[][] jointNorm = new double[N][2];
for (int t2 = 0; t2 < N; t2++) {
jointNorm[t2][JOINT_NORM_VAL_COLUMN] = Math.max(xyNorms[t2][0], xyNorms[t2][1]);
@ -332,7 +331,7 @@ public class MutualInfoCalculatorMultiVariateKraskov2
// Compute eps_x and eps_y for this time step:
// First get x and y norms to all neighbours
// (note that norm of point t to itself will be set to infinity).
double[][] xyNorms = EuclideanUtils.computeNorms(data1, data2, t);
double[][] xyNorms = normCalculator.computeNorms(data1, data2, t);
double[][] jointNorm = new double[N][2];
for (int t2 = 0; t2 < N; t2++) {
jointNorm[t2][JOINT_NORM_VAL_COLUMN] = Math.max(xyNorms[t2][0], xyNorms[t2][1]);

View File

@ -47,6 +47,7 @@ public class MutualInfoCalculatorMultiVariateWithDiscreteKraskov implements Mutu
protected double mi;
protected boolean miComputed;
protected EuclideanUtils normCalculator;
// Storage for the norms from each observation to each other one
protected double[][] xNorms;
// Keep the norms each time (making reordering very quick)
@ -74,6 +75,7 @@ public class MutualInfoCalculatorMultiVariateWithDiscreteKraskov implements Mutu
public MutualInfoCalculatorMultiVariateWithDiscreteKraskov() {
super();
k = 1; // by default
normCalculator = new EuclideanUtils(EuclideanUtils.NORM_MAX_NORM);
}
/**
@ -95,6 +97,17 @@ public class MutualInfoCalculatorMultiVariateWithDiscreteKraskov implements Mutu
}
/**
* Sets properties for the calculator.
* Valid properties include:
* <ul>
* <li>{@link #PROP_K} - number of neighbouring points in joint kernel space</li>
* <li>{@link #PROP_NORM_TYPE}</li> - normalization type to apply to
* working out the norms between the points in each marginal space.
* Options are defined by {@link EuclideanUtils#setNormToUse(String)} -
* default is {@link EuclideanUtils#NORM_MAX_NORM}.
* <li>{@link #PROP_NORMALISE} - whether to normalise the individual
* variables (true by default)</li>
* </ul>
*
* @param propertyName name of the property to set
* @param propertyValue value to set on that property
@ -103,7 +116,7 @@ public class MutualInfoCalculatorMultiVariateWithDiscreteKraskov implements Mutu
if (propertyName.equalsIgnoreCase(PROP_K)) {
k = Integer.parseInt(propertyValue);
} else if (propertyName.equalsIgnoreCase(PROP_NORM_TYPE)) {
EuclideanUtils.setNormToUse(propertyValue);
normCalculator.setNormToUse(propertyValue);
} else if (propertyName.equalsIgnoreCase(PROP_NORMALISE)) {
normalise = Boolean.parseBoolean(propertyValue);
}
@ -184,7 +197,7 @@ public class MutualInfoCalculatorMultiVariateWithDiscreteKraskov implements Mutu
continue;
}
// Compute norm in the continuous space
xNorms[t][t2] = EuclideanUtils.norm(continuousData[t], continuousData[t2]);
xNorms[t][t2] = normCalculator.norm(continuousData[t], continuousData[t2]);
}
}
}
@ -363,7 +376,7 @@ public class MutualInfoCalculatorMultiVariateWithDiscreteKraskov implements Mutu
continue;
}
// Compute norm in the continuous space
norms[t2] = EuclideanUtils.norm(continuousData[t], continuousData[t2]);
norms[t2] = normCalculator.norm(continuousData[t], continuousData[t2]);
}
// Then find the k closest neighbours in the same discrete bin
@ -530,7 +543,7 @@ public class MutualInfoCalculatorMultiVariateWithDiscreteKraskov implements Mutu
double[] norms = new double[continuousData.length];
for (int t2 = 0; t2 < continuousData.length; t2++) {
// Compute norm in the continuous space
norms[t2] = EuclideanUtils.norm(continuousNewStates[t], continuousData[t2]);
norms[t2] = normCalculator.norm(continuousNewStates[t], continuousData[t2]);
}
// Then find the k closest neighbours in the same discrete bin

View File

@ -17,10 +17,19 @@ public class EuclideanUtils {
public static final String NORM_EUCLIDEAN_NORMALISED_STRING = "EUCLIDEAN_NORMALISED";
public static final int NORM_MAX_NORM = 2;
public static final String NORM_MAX_NORM_STRING = "MAX_NORM";
private static int normToUse = 0;
// Track which norm we should use here
private int normToUse = 0;
public EuclideanUtils() {
super();
/**
* Construct a EuclideanUtils object, to take norms of the given type
*
* @param normToUse norm type, one of
* {@link #NORM_EUCLIDEAN_STRING},
* {@link #NORM_EUCLIDEAN_NORMALISED_STRING},
* or {@link #NORM_MAX_NORM_STRING}
*/
public EuclideanUtils(int normToUse) {
this.normToUse = normToUse;
}
public static double[] computeMinEuclideanDistances(double[][] observations) {
@ -144,7 +153,17 @@ public class EuclideanUtils {
return minDistance;
}
public static double maxJointSpaceNorm(double[] x1, double[] y1,
/**
* Return the max norm out of the two norms (x1:x2) and (y1:y2),
* using the configured norm type
*
* @param x1
* @param y1
* @param x2
* @param y2
* @return the max of the two norms
*/
public double maxJointSpaceNorm(double[] x1, double[] y1,
double[] x2, double[] y2) {
return Math.max(norm(x1, x2), norm(y1,y2));
}
@ -156,7 +175,7 @@ public class EuclideanUtils {
* @param x2
* @return
*/
public static double norm(double[] x1, double[] x2) {
public double norm(double[] x1, double[] x2) {
switch (normToUse) {
case NORM_EUCLIDEAN_NORMALISED:
return euclideanNorm(x1, x2) / Math.sqrt(x1.length);
@ -207,7 +226,7 @@ public class EuclideanUtils {
}
/**
* Compute the x and y norms of all other points from
* Compute the x and y configured norms of all other points from
* the data points at time step t.
* Puts norms of t from itself as infinity, which is useful
* when counting the number of points closer than epsilon say.
@ -216,7 +235,7 @@ public class EuclideanUtils {
* @param mvTimeSeries2
* @return
*/
public static double[][] computeNorms(double[][] mvTimeSeries1,
public double[][] computeNorms(double[][] mvTimeSeries1,
double[][] mvTimeSeries2, int t) {
int timeSteps = mvTimeSeries1.length;
@ -246,7 +265,7 @@ public class EuclideanUtils {
* @param mvTimeSeries3
* @return
*/
public static double[][] computeNorms(double[][] mvTimeSeries1,
public double[][] computeNorms(double[][] mvTimeSeries1,
double[][] mvTimeSeries2, double[][] mvTimeSeries3, int t) {
int timeSteps = mvTimeSeries1.length;
@ -302,8 +321,8 @@ public class EuclideanUtils {
*
* @param normType
*/
public static void setNormToUse(int normType) {
normToUse = normType;
public void setNormToUse(int normType) {
this.normToUse = normType;
}
/**
@ -311,7 +330,7 @@ public class EuclideanUtils {
*
* @param normType
*/
public static void setNormToUse(String normType) {
public void setNormToUse(String normType) {
if (normType.equalsIgnoreCase(NORM_EUCLIDEAN_NORMALISED_STRING)) {
normToUse = NORM_EUCLIDEAN_NORMALISED;
} else if (normType.equalsIgnoreCase(NORM_MAX_NORM_STRING)) {
@ -321,7 +340,7 @@ public class EuclideanUtils {
}
}
public static String getNormInUse() {
public String getNormInUse() {
switch (normToUse) {
case NORM_EUCLIDEAN_NORMALISED:
return NORM_EUCLIDEAN_NORMALISED_STRING;