diff --git a/java/source/infodynamics/measures/continuous/ActiveInfoStorageCalculatorViaMutualInfo.java b/java/source/infodynamics/measures/continuous/ActiveInfoStorageCalculatorViaMutualInfo.java
index 03cf050..5fe813a 100755
--- a/java/source/infodynamics/measures/continuous/ActiveInfoStorageCalculatorViaMutualInfo.java
+++ b/java/source/infodynamics/measures/continuous/ActiveInfoStorageCalculatorViaMutualInfo.java
@@ -18,6 +18,7 @@
package infodynamics.measures.continuous;
+import java.util.Iterator;
import java.util.Vector;
import infodynamics.utils.EmpiricalMeasurementDistribution;
@@ -79,10 +80,15 @@ public class ActiveInfoStorageCalculatorViaMutualInfo implements
protected boolean debug = false;
/**
- * Storage for source observations supplied via {@link #addObservations(double[])}
+ * Storage for observations supplied via {@link #addObservations(double[])}
* type calls
*/
protected Vector vectorOfObservationTimeSeries;
+ /**
+ * Storage for validity arrays for supplied observations.
+ * Entries are null where the whole corresponding observation time-series is valid
+ */
+ protected Vector vectorOfValidityOfObservations;
/**
* Construct using an instantiation of the named MI calculator
@@ -164,6 +170,8 @@ public class ActiveInfoStorageCalculatorViaMutualInfo implements
public void initialise(int k, int tau) throws Exception {
this.k = k;
this.tau = tau;
+ vectorOfObservationTimeSeries = null;
+ vectorOfValidityOfObservations = null;
}
/**
@@ -248,6 +256,7 @@ public class ActiveInfoStorageCalculatorViaMutualInfo implements
@Override
public void startAddObservations() {
vectorOfObservationTimeSeries = new Vector();
+ vectorOfValidityOfObservations = new Vector();
}
/* (non-Javadoc)
@@ -257,6 +266,7 @@ public class ActiveInfoStorageCalculatorViaMutualInfo implements
public void addObservations(double[] observations) throws Exception {
// Store these observations in our vector for now
vectorOfObservationTimeSeries.add(observations);
+ vectorOfValidityOfObservations.add(null); // All observations were valid
}
/**
@@ -282,6 +292,33 @@ public class ActiveInfoStorageCalculatorViaMutualInfo implements
miCalc.addObservations(currentDestPastVectors, currentDestNextVectors);
}
+ /**
+ * Protected method to internally parse and submit observations through
+ * to the underlying MI calculator once any internal parameter settings
+ * have been finalised (in the case of automatically determining the embedding
+ * parameters).
+ * This is done given a time-series of booleans indicating whether each entry
+ * is valid
+ *
+ * @param observations time series of observations
+ * @param valid a time series (with indices the same as observations) indicating
+ * whether the entry in observations at that index is valid; we only take vectors
+ * as samples to add to the observation set where all points in the time series
+ * (even between points in the embedded k-vector with embedding delays) are valid.
+ * @throws Exception
+ */
+ protected void addObservationsAfterParamsDetermined(double[] observations, boolean[] valid) throws Exception {
+
+ // compute the start and end times using our determined embedding parameters:
+ Vector startAndEndTimePairs = computeStartAndEndTimePairs(valid);
+
+ for (int[] timePair : startAndEndTimePairs) {
+ int startTime = timePair[0];
+ int endTime = timePair[1];
+ addObservationsAfterParamsDetermined(MatrixUtils.select(observations, startTime, endTime - startTime + 1));
+ }
+ }
+
/* (non-Javadoc)
* @see infodynamics.measures.continuous.ActiveInfoStorageCalculator#addObservations(double[], int, int)
*/
@@ -300,7 +337,7 @@ public class ActiveInfoStorageCalculatorViaMutualInfo implements
* Child implementations do not need to override this default empty implementation
* if no new functionality is required.
*/
- public void preFinaliseAddObservations() throws Exception {
+ protected void preFinaliseAddObservations() throws Exception {
// Empty implementation supplied by default.
}
@@ -316,10 +353,18 @@ public class ActiveInfoStorageCalculatorViaMutualInfo implements
miCalc.initialise(k, 1);
miCalc.startAddObservations();
// Send all of the observations through:
+ Iterator validityIterator = vectorOfValidityOfObservations.iterator();
for (double[] observations : vectorOfObservationTimeSeries) {
- addObservationsAfterParamsDetermined(observations);
+ boolean[] validity = validityIterator.next();
+ if (validity == null) {
+ // Add the whole time-series
+ addObservationsAfterParamsDetermined(observations);
+ } else {
+ addObservationsAfterParamsDetermined(observations, validity);
+ }
}
vectorOfObservationTimeSeries = null; // No longer required
+ vectorOfValidityOfObservations = null;
// TODO do we need to throw an exception if there are no observations to add?
miCalc.finaliseAddObservations();
@@ -331,15 +376,10 @@ public class ActiveInfoStorageCalculatorViaMutualInfo implements
@Override
public void setObservations(double[] observations, boolean[] valid)
throws Exception {
- Vector startAndEndTimePairs = computeStartAndEndTimePairs(valid);
-
- // We've found the set of start and end times for this pair
startAddObservations();
- for (int[] timePair : startAndEndTimePairs) {
- int startTime = timePair[0];
- int endTime = timePair[1];
- addObservations(observations, startTime, endTime - startTime + 1);
- }
+ // Add these observations and the indication of their validity
+ vectorOfObservationTimeSeries.add(observations);
+ vectorOfValidityOfObservations.add(valid);
finaliseAddObservations();
}
diff --git a/java/source/infodynamics/measures/continuous/TransferEntropyCalculatorViaCondMutualInfo.java b/java/source/infodynamics/measures/continuous/TransferEntropyCalculatorViaCondMutualInfo.java
index f94a0cc..f6da00c 100755
--- a/java/source/infodynamics/measures/continuous/TransferEntropyCalculatorViaCondMutualInfo.java
+++ b/java/source/infodynamics/measures/continuous/TransferEntropyCalculatorViaCondMutualInfo.java
@@ -21,6 +21,7 @@ package infodynamics.measures.continuous;
import infodynamics.utils.EmpiricalMeasurementDistribution;
import infodynamics.utils.MatrixUtils;
+import java.util.Iterator;
import java.util.Vector;
/**
@@ -102,6 +103,28 @@ public class TransferEntropyCalculatorViaCondMutualInfo implements
*/
protected boolean debug = false;
+ /**
+ * Storage for source observations supplied via {@link #addObservations(double[], double[])} etc.
+ */
+ protected Vector vectorOfSourceTimeSeries;
+
+ /**
+ * Storage for destination observations supplied via {@link #addObservations(double[], double[])} etc.
+ */
+ protected Vector vectorOfDestinationTimeSeries;
+
+ /**
+ * Storage for validity arrays for supplied source observations.
+ * Entries are null where the whole corresponding observation time-series is valid
+ */
+ protected Vector vectorOfValidityOfSource;
+
+ /**
+ * Storage for validity arrays for supplied destination observations.
+ * Entries are null where the whole corresponding observation time-series is valid
+ */
+ protected Vector vectorOfValidityOfDestination;
+
/**
* Construct a transfer entropy calculator using an instance of
* condMiCalculatorClassName as the underlying conditional mutual information calculator.
@@ -199,19 +222,30 @@ public class TransferEntropyCalculatorViaCondMutualInfo implements
this.l_tau = l_tau;
this.delay = delay;
- // Now check which point we can start taking observations from in any
- // addObservations call. These two integers represent the last
- // point of the destination embedding, in the cases where the destination
- // embedding itself determines where we can start taking observations, or
- // the case where the source embedding plus delay is longer and so determines
- // where we can start taking observations.
+ setStartTimeForFirstDestEmbedding();
+
+ vectorOfSourceTimeSeries = null;
+ vectorOfDestinationTimeSeries = null;
+ vectorOfValidityOfSource = null;
+ vectorOfValidityOfDestination = null;
+ }
+
+ /**
+ * Protected internal method to
+ * set the point at which we can start taking observations from in any
+ * addObservations call.
+ */
+ protected void setStartTimeForFirstDestEmbedding() {
+ // These two integers represent the last
+ // point of the destination embedding, in the cases where the destination
+ // embedding itself determines where we can start taking observations, or
+ // the case where the source embedding plus delay is longer and so determines
+ // where we can start taking observations.
int startTimeBasedOnDestPast = (k-1)*k_tau;
int startTimeBasedOnSourcePast = (l-1)*l_tau + delay - 1;
startTimeForFirstDestEmbedding = Math.max(startTimeBasedOnDestPast, startTimeBasedOnSourcePast);
-
- condMiCalc.initialise(l, 1, k);
}
-
+
/**
* Sets properties for the TE calculator.
* New property values are not guaranteed to take effect until the next call
@@ -277,37 +311,40 @@ public class TransferEntropyCalculatorViaCondMutualInfo implements
@Override
public void setObservations(double[] source, double[] destination) throws Exception {
-
- if (source.length != destination.length) {
- throw new Exception(String.format("Source and destination lengths (%d and %d) must match!",
- source.length, destination.length));
- }
- if (source.length < startTimeForFirstDestEmbedding + 2) {
- // There are no observations to add here, the time series is too short
- throw new Exception("Not enough observations to set here given k, k_tau, l, l_tau and delay parameters");
- }
- double[][] currentDestPastVectors =
- MatrixUtils.makeDelayEmbeddingVector(destination, k, k_tau,
- startTimeForFirstDestEmbedding,
- destination.length - startTimeForFirstDestEmbedding - 1);
- double[][] currentDestNextVectors =
- MatrixUtils.makeDelayEmbeddingVector(destination, 1,
- startTimeForFirstDestEmbedding + 1,
- destination.length - startTimeForFirstDestEmbedding - 1);
- double[][] currentSourcePastVectors =
- MatrixUtils.makeDelayEmbeddingVector(source, l, l_tau,
- startTimeForFirstDestEmbedding + 1 - delay,
- source.length - startTimeForFirstDestEmbedding - 1);
- condMiCalc.setObservations(currentSourcePastVectors, currentDestNextVectors, currentDestPastVectors);
+ startAddObservations();
+ addObservations(source, destination);
+ finaliseAddObservations();
}
@Override
public void startAddObservations() {
- condMiCalc.startAddObservations();
+ vectorOfSourceTimeSeries = new Vector();
+ vectorOfDestinationTimeSeries = new Vector();
+ vectorOfValidityOfSource = new Vector();
+ vectorOfValidityOfDestination = new Vector();
}
@Override
- public void addObservations(double[] source, double[] destination) throws Exception {
+ public void addObservations(double[] source, double[] destination)
+ throws Exception {
+ // Store these observations in our vector for now
+ vectorOfSourceTimeSeries.add(source);
+ vectorOfDestinationTimeSeries.add(destination);
+ vectorOfValidityOfSource.add(null); // All observations were valid
+ vectorOfValidityOfDestination.add(null); // All observations were valid
+ }
+
+ /**
+ * Protected method to internally parse and submit observations through
+ * to the underlying conditional MI calculator once any internal parameter settings
+ * have been finalised (in the case of automatically determining the embedding
+ * parameters)
+ *
+ * @param source time series of source observations
+ * @param destination time series of destination observations
+ * @throws Exception
+ */
+ protected void addObservationsAfterParamsDetermined(double[] source, double[] destination) throws Exception {
if (source.length != destination.length) {
throw new Exception(String.format("Source and destination lengths (%d and %d) must match!",
source.length, destination.length));
@@ -333,6 +370,37 @@ public class TransferEntropyCalculatorViaCondMutualInfo implements
condMiCalc.addObservations(currentSourcePastVectors, currentDestNextVectors, currentDestPastVectors);
}
+ /**
+ * Protected method to internally parse and submit observations through
+ * to the underlying conditional MI calculator once any internal parameter settings
+ * have been finalised (in the case of automatically determining the embedding
+ * parameters)
+ * This is done given time-series of booleans indicating whether each entry
+ * is valid
+ *
+ * @param source time series of source observations
+ * @param destination time series of destination observations
+ * @param sourceValid array (with indices the same as source) indicating whether
+ * the source at that index is valid.
+ * @param destValid array (with indices the same as destination) indicating whether
+ * the destination at that index is valid.
+ * @throws Exception
+ */
+ protected void addObservationsAfterParamsDetermined(double[] source, double[] destination,
+ boolean[] sourceValid, boolean[] destValid) throws Exception {
+
+ // Compute the start and end time pairs using our embedding parameters:
+ Vector startAndEndTimePairs = computeStartAndEndTimePairs(sourceValid, destValid);
+
+ for (int[] timePair : startAndEndTimePairs) {
+ int startTime = timePair[0];
+ int endTime = timePair[1];
+ addObservationsAfterParamsDetermined(
+ MatrixUtils.select(source, startTime, endTime - startTime + 1),
+ MatrixUtils.select(destination, startTime, endTime - startTime + 1));
+ }
+ }
+
@Override
public void addObservations(double[] source, double[] destination,
int startTime, int numTimeSteps) throws Exception {
@@ -348,8 +416,49 @@ public class TransferEntropyCalculatorViaCondMutualInfo implements
MatrixUtils.select(destination, startTime, numTimeSteps));
}
+ /**
+ * Hook in case child implementations need to perform any processing on the
+ * observation time series prior to their being processed and supplied
+ * to the underlying MI calculator.
+ * Primarily this is to allow the child implementation to automatically determine
+ * embedding parameters if desired.
+ * Child implementations do not need to override this default empty implementation
+ * if no new functionality is required.
+ */
+ protected void preFinaliseAddObservations() throws Exception {
+ // Empty implementation supplied by default.
+ }
+
@Override
public void finaliseAddObservations() throws Exception {
+ // Auto embed if required
+ preFinaliseAddObservations();
+
+ // Initialise the conditional MI calculator, including any auto-embedding length
+ condMiCalc.initialise(l, 1, k);
+ condMiCalc.startAddObservations();
+ // Send all of the observations through:
+ Iterator destIterator = vectorOfDestinationTimeSeries.iterator();
+ Iterator sourceValidityIterator = vectorOfValidityOfSource.iterator();
+ Iterator destValidityIterator = vectorOfValidityOfDestination.iterator();
+ for (double[] source : vectorOfSourceTimeSeries) {
+ double[] destination = destIterator.next();
+ boolean[] sourceValidity = sourceValidityIterator.next();
+ boolean[] destValidity = destValidityIterator.next();
+ if (sourceValidity == null) {
+ // Add the whole time-series
+ addObservationsAfterParamsDetermined(source, destination);
+ } else {
+ addObservationsAfterParamsDetermined(source, destination,
+ sourceValidity, destValidity);
+ }
+ }
+ vectorOfSourceTimeSeries = null; // No longer required
+ vectorOfDestinationTimeSeries = null; // No longer required
+ vectorOfValidityOfSource = null;
+ vectorOfValidityOfDestination = null;
+
+ // TODO do we need to throw an exception if there are no observations to add?
condMiCalc.finaliseAddObservations();
}
@@ -357,15 +466,13 @@ public class TransferEntropyCalculatorViaCondMutualInfo implements
public void setObservations(double[] source, double[] destination,
boolean[] sourceValid, boolean[] destValid) throws Exception {
- Vector startAndEndTimePairs = computeStartAndEndTimePairs(sourceValid, destValid);
-
- // We've found the set of start and end times for this pair
startAddObservations();
- for (int[] timePair : startAndEndTimePairs) {
- int startTime = timePair[0];
- int endTime = timePair[1];
- addObservations(source, destination, startTime, endTime - startTime + 1);
- }
+ // Add these observations and the indication of their validity
+ // for later analysis:
+ vectorOfSourceTimeSeries.add(source);
+ vectorOfDestinationTimeSeries.add(destination);
+ vectorOfValidityOfSource.add(sourceValid);
+ vectorOfValidityOfDestination.add(destValid);
finaliseAddObservations();
}
diff --git a/java/source/infodynamics/measures/continuous/kraskov/ActiveInfoStorageCalculatorKraskov.java b/java/source/infodynamics/measures/continuous/kraskov/ActiveInfoStorageCalculatorKraskov.java
index 22edcdf..163f845 100755
--- a/java/source/infodynamics/measures/continuous/kraskov/ActiveInfoStorageCalculatorKraskov.java
+++ b/java/source/infodynamics/measures/continuous/kraskov/ActiveInfoStorageCalculatorKraskov.java
@@ -202,7 +202,10 @@ public class ActiveInfoStorageCalculatorKraskov
* and embedding delay ({@link #TAU_PROP_NAME}). Default is {@link #AUTO_EMBED_METHOD_NONE} meaning
* values are set manually; other accepted values include: {@link #AUTO_EMBED_METHOD_RAGWITZ} for use
* of the Ragwitz criteria (searching up to {@link #PROP_K_SEARCH_MAX} and
- * {@link #PROP_TAU_SEARCH_MAX})
+ * {@link #PROP_TAU_SEARCH_MAX}). Use of any value other than {@link #AUTO_EMBED_METHOD_NONE}
+ * will lead to any previous settings for k and tau (via e.g. {@link #initialise(int, int)} or
+ * auto-embedding during previous calculations) will be overwritten after observations
+ * are supplied.
* {@link #PROP_K_SEARCH_MAX} -- maximum embedded history length to search
* up to if automatically determining the embedding parameters (as set by
* {@link #PROP_AUTO_EMBED_METHOD}); default is 1
diff --git a/java/source/infodynamics/measures/continuous/kraskov/TransferEntropyCalculatorKraskov.java b/java/source/infodynamics/measures/continuous/kraskov/TransferEntropyCalculatorKraskov.java
index 467f817..4de878c 100755
--- a/java/source/infodynamics/measures/continuous/kraskov/TransferEntropyCalculatorKraskov.java
+++ b/java/source/infodynamics/measures/continuous/kraskov/TransferEntropyCalculatorKraskov.java
@@ -20,6 +20,7 @@ package infodynamics.measures.continuous.kraskov;
import java.util.Hashtable;
+import infodynamics.measures.continuous.ActiveInfoStorageCalculator;
import infodynamics.measures.continuous.ConditionalMutualInfoCalculatorMultiVariate;
import infodynamics.measures.continuous.TransferEntropyCalculator;
import infodynamics.measures.continuous.TransferEntropyCalculatorViaCondMutualInfo;
@@ -49,7 +50,12 @@ import infodynamics.measures.continuous.TransferEntropyCalculatorViaCondMutualIn
* {@link ConditionalMutualInfoCalculatorMultiVariateKraskov#setProperty(String, String)}
* as outlined
* in {@link TransferEntropyCalculatorViaCondMutualInfo#setProperty(String, String)});
- * as well as for {@link #PROP_KRASKOV_ALG_NUM}.
+ * as well as for {@link #PROP_KRASKOV_ALG_NUM}.
+ * Embedding parameters may be automatically determined as per the Ragwitz criteria
+ * by setting the property {@link #PROP_AUTO_EMBED_METHOD} to {@link #AUTO_EMBED_METHOD_RAGWITZ}
+ * or {@link #AUTO_EMBED_METHOD_RAGWITZ_DEST_ONLY}
+ * (plus additional parameter settings for this).
+ *
* Computed values are in nats, not bits!
*
*
@@ -73,6 +79,8 @@ import infodynamics.measures.continuous.TransferEntropyCalculatorViaCondMutualIn
*
* "Local information transfer as a spatiotemporal filter for complex systems"
* Physical Review E 77, 026110, 2008.
+ * Ragwitz and Kantz, "Markov models from data by simple nonlinear time series
+ * predictors in delay embedding spaces", Physical Review E, vol 65, 056201 (2002).
*
*
* @author Joseph Lizier (email,
@@ -108,6 +116,71 @@ public class TransferEntropyCalculatorKraskov
*/
protected Hashtable props;
+ /**
+ * Property name for the auto-embedding method. Defaults to {@link #AUTO_EMBED_METHOD_NONE}
+ */
+ public static final String PROP_AUTO_EMBED_METHOD = "AUTO_EMBED_METHOD";
+ /**
+ * Valid value for the property {@link #PROP_AUTO_EMBED_METHOD} indicating that
+ * no auto embedding should be done (i.e. to use manually supplied parameters)
+ */
+ public static final String AUTO_EMBED_METHOD_NONE = "NONE";
+ /**
+ * Valid value for the property {@link #PROP_AUTO_EMBED_METHOD} indicating that
+ * the Ragwitz optimisation technique should be used for automatic embedding
+ * for both source and destination time-series
+ */
+ public static final String AUTO_EMBED_METHOD_RAGWITZ = "RAGWITZ";
+ /**
+ * Valid value for the property {@link #PROP_AUTO_EMBED_METHOD} indicating that
+ * the Ragwitz optimisation technique should be used for automatic embedding
+ * for the destination time-series only
+ */
+ public static final String AUTO_EMBED_METHOD_RAGWITZ_DEST_ONLY = "RAGWITZ_DEST_ONLY";
+ /**
+ * Internal variable tracking what type of auto embedding (if any)
+ * we are using
+ */
+ protected String autoEmbeddingMethod = AUTO_EMBED_METHOD_NONE;
+
+ /**
+ * Property name for maximum embedding lengths (i.e. k for destination, and l for source if we're auto-embedding
+ * the source as well) for the auto-embedding search. Defaults to 1
+ */
+ public static final String PROP_K_SEARCH_MAX = "AUTO_EMBED_K_SEARCH_MAX";
+ /**
+ * Internal variable for storing the maximum embedding length to search up to for
+ * automating the parameters.
+ */
+ protected int k_search_max = 1;
+
+ /**
+ * Property name for maximum embedding delay (i.e. k_tau for destination, and l_tau for source if we're auto-embedding
+ * the source as well) for the auto-embedding search. Defaults to 1
+ */
+ public static final String PROP_TAU_SEARCH_MAX = "AUTO_EMBED_TAU_SEARCH_MAX";
+ /**
+ * Internal variable for storing the maximum embedding delay to search up to for
+ * automating the parameters.
+ */
+ protected int tau_search_max = 1;
+
+ /**
+ * Property name for the number of nearest neighbours to use for the auto-embedding search (Ragwitz criteria).
+ * Defaults to match the value in use for {@link MutualInfoCalculatorMultiVariateKraskov#PROP_K}
+ */
+ public static final String PROP_RAGWITZ_NUM_NNS = "AUTO_EMBED_RAGWITZ_NUM_NNS";
+ /**
+ * Internal variable for storing the number of nearest neighbours to use for the
+ * auto embedding search (Ragwitz criteria)
+ */
+ protected int ragwitz_num_nns = 1;
+ /**
+ * Internal variable to track whether the property {@link #PROP_RAGWITZ_NUM_NNS} has been
+ * set yet
+ */
+ protected boolean ragwitz_num_nns_set = false;
+
/**
* Creates a new instance of the Kraskov-estimate style transfer entropy calculator
*
@@ -185,6 +258,29 @@ public class TransferEntropyCalculatorKraskov
* values should represent, include:
*
* - {@link #PROP_KRASKOV_ALG_NUM} -- which Kraskov algorithm number to use (1 or 2).
+ * - {@link #PROP_AUTO_EMBED_METHOD} -- method by which the calculator
+ * automatically determines the embedding history length ({@link #K_PROP_NAME})
+ * and embedding delay ({@link #TAU_PROP_NAME}) for destination and potentially source.
+ * Default is {@link #AUTO_EMBED_METHOD_NONE} meaning
+ * values are set manually; other accepted values include: {@link #AUTO_EMBED_METHOD_RAGWITZ} for use
+ * of the Ragwitz criteria for both source and destination (searching up to {@link #PROP_K_SEARCH_MAX} and
+ * {@link #PROP_TAU_SEARCH_MAX}), and {@link #AUTO_EMBED_METHOD_RAGWITZ_DEST_ONLY} for use
+ * of the Ragwitz criteria for the destination only.
+ * Use of any value other than {@link #AUTO_EMBED_METHOD_NONE}
+ * will lead to previous settings for embedding lengths and delays (via e.g. {@link #initialise(int, int)} or
+ * auto-embedding during previous calculations) for the destination and perhaps source to
+ * be overwritten after observations are supplied.
+ * - {@link #PROP_K_SEARCH_MAX} -- maximum embedded history length to search
+ * up to if automatically determining the embedding parameters (as set by
+ * {@link #PROP_AUTO_EMBED_METHOD}) for the time-series to be embedded; default is 1
+ * - {@link #PROP_TAU_SEARCH_MAX} -- maximum embedded history length to search
+ * up to if automatically determining the embedding parameters (as set by
+ * {@link #PROP_AUTO_EMBED_METHOD}) for the time-series to be embedded; default is 1
+ * - {@link #PROP_RAGWITZ_NUM_NNS} -- number of nearest neighbours to use
+ * in the auto-embedding if the property {@link #PROP_AUTO_EMBED_METHOD}
+ * has been set to {@link #AUTO_EMBED_METHOD_RAGWITZ} or {@link #AUTO_EMBED_METHOD_RAGWITZ_DEST_ONLY}.
+ * Defaults to the property value
+ * set for {@link ConditionalMutualInfoCalculatorMultiVariateKraskov#PROP_K}
* - Any properties accepted by {@link TransferEntropyCalculatorViaCondMutualInfo#setProperty(String, String)}
* - Or properties accepted by the underlying
* {@link ConditionalMutualInfoCalculatorMultiVariateKraskov#setProperty(String, String)} implementation.
@@ -215,6 +311,19 @@ public class TransferEntropyCalculatorKraskov
System.out.println(this.getClass().getSimpleName() + ": Set property " + propertyName +
" to " + propertyValue);
}
+ } else if (propertyName.equalsIgnoreCase(PROP_AUTO_EMBED_METHOD)) {
+ // New method set for determining the embedding parameters
+ autoEmbeddingMethod = propertyValue;
+ } else if (propertyName.equalsIgnoreCase(PROP_K_SEARCH_MAX)) {
+ // Set max embedding history length for auto determination of embedding
+ k_search_max = Integer.parseInt(propertyValue);
+ } else if (propertyName.equalsIgnoreCase(PROP_TAU_SEARCH_MAX)) {
+ // Set maximum embedding delay for auto determination of embedding
+ tau_search_max = Integer.parseInt(propertyValue);
+ } else if (propertyName.equalsIgnoreCase(PROP_RAGWITZ_NUM_NNS)) {
+ // Set the number of nearest neighbours to use in case of Ragwitz auto embedding:
+ ragwitz_num_nns = Integer.parseInt(propertyValue);
+ ragwitz_num_nns_set = true;
} else {
// Assume it was a property for the parent class or underlying conditional MI calculator
super.setProperty(propertyName, propertyValue);
@@ -226,10 +335,94 @@ public class TransferEntropyCalculatorKraskov
public String getProperty(String propertyName) throws Exception {
if (propertyName.equalsIgnoreCase(PROP_KRASKOV_ALG_NUM)) {
return Integer.toString(kraskovAlgorithmNumber);
+ } else if (propertyName.equalsIgnoreCase(PROP_AUTO_EMBED_METHOD)) {
+ return autoEmbeddingMethod;
+ } else if (propertyName.equalsIgnoreCase(PROP_K_SEARCH_MAX)) {
+ return Integer.toString(k_search_max);
+ } else if (propertyName.equalsIgnoreCase(PROP_TAU_SEARCH_MAX)) {
+ return Integer.toString(tau_search_max);
+ } else if (propertyName.equalsIgnoreCase(PROP_RAGWITZ_NUM_NNS)) {
+ if (ragwitz_num_nns_set) {
+ return Integer.toString(ragwitz_num_nns);
+ } else {
+ return condMiCalc.getProperty(ConditionalMutualInfoCalculatorMultiVariateKraskov.PROP_K);
+ }
} else {
// Assume it was a property for the parent class or underlying conditional MI calculator
return super.getProperty(propertyName);
}
}
+ @Override
+ public void preFinaliseAddObservations() throws Exception {
+ // Automatically determine the embedding parameters for the given time series
+
+ if (autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_NONE)) {
+ return;
+ }
+ // Else we need to auto embed
+
+ // If we need to check which embedding method later:
+ // if (autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_RAGWITZ) ||
+ // autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_RAGWITZ_DEST_ONLY)) {
+
+ // Use a Kraskov AIS calculator to embed both time-series individually:
+ ActiveInfoStorageCalculatorKraskov aisCalc = new ActiveInfoStorageCalculatorKraskov();
+ // Set the properties for the underlying MI Kraskov calculator here to match ours:
+ for (String key : props.keySet()) {
+ aisCalc.setProperty(key, props.get(key));
+ }
+ // Set the auto-embedding properties as we require:
+ aisCalc.setProperty(ActiveInfoStorageCalculatorKraskov.PROP_AUTO_EMBED_METHOD,
+ ActiveInfoStorageCalculatorKraskov.AUTO_EMBED_METHOD_RAGWITZ);
+ aisCalc.setProperty(ActiveInfoStorageCalculatorKraskov.PROP_K_SEARCH_MAX,
+ Integer.toString(k_search_max));
+ aisCalc.setProperty(ActiveInfoStorageCalculatorKraskov.PROP_TAU_SEARCH_MAX,
+ Integer.toString(tau_search_max));
+ // In case !ragwitz_num_nns_set and our condMiCalc has a different default number of
+ // kNNs for Kraskov search than miCalc, we had best supply the number directly here:
+ aisCalc.setProperty(ActiveInfoStorageCalculatorKraskov.PROP_RAGWITZ_NUM_NNS,
+ getProperty(PROP_RAGWITZ_NUM_NNS));
+
+ // Embed the destination with the Ragwitz criteria:
+ if (debug) {
+ System.out.println("Starting embedding of destination:");
+ }
+ aisCalc.initialise();
+ aisCalc.startAddObservations();
+ for (double[] destination : vectorOfDestinationTimeSeries) {
+ aisCalc.addObservations(destination);
+ }
+ aisCalc.finaliseAddObservations();
+ // Set the auto-embedding parameters for the destination:
+ k = Integer.parseInt(aisCalc.getProperty(ActiveInfoStorageCalculator.K_PROP_NAME));
+ k_tau = Integer.parseInt(aisCalc.getProperty(ActiveInfoStorageCalculator.TAU_PROP_NAME));
+ if (debug) {
+ System.out.printf("Embedding parameters for destination set to k=%d,k_tau=%d\n",
+ k, k_tau);
+ }
+
+ if (autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_RAGWITZ)) {
+ // Embed the source also with the Ragwitz criteria:
+ if (debug) {
+ System.out.println("Starting embedding of source:");
+ }
+ aisCalc.initialise();
+ aisCalc.startAddObservations();
+ for (double[] source : vectorOfSourceTimeSeries) {
+ aisCalc.addObservations(source);
+ }
+ aisCalc.finaliseAddObservations();
+ // Set the auto-embedding parameters for the source:
+ l = Integer.parseInt(aisCalc.getProperty(ActiveInfoStorageCalculator.K_PROP_NAME));
+ l_tau = Integer.parseInt(aisCalc.getProperty(ActiveInfoStorageCalculator.TAU_PROP_NAME));
+ if (debug) {
+ System.out.printf("Embedding parameters for source set to l=%d,l_tau=%d\n",
+ l, l_tau);
+ }
+ }
+
+ // Now that embedding parameters are finalised:
+ setStartTimeForFirstDestEmbedding();
+ }
}