mirror of https://github.com/jlizier/jidt
Adding auto embedding via Ragwitz criteria for Kraskov Transfer Entropy calculator. This fixes Issue 38.
Also patched AIS calculator to handle observations supplied with validity indicator when auto embedding is undertaken.
This commit is contained in:
parent
8393429e26
commit
90fd9fbe89
|
|
@ -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<double[]> vectorOfObservationTimeSeries;
|
||||
/**
|
||||
* Storage for validity arrays for supplied observations.
|
||||
* Entries are null where the whole corresponding observation time-series is valid
|
||||
*/
|
||||
protected Vector<boolean[]> 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<double[]>();
|
||||
vectorOfValidityOfObservations = new Vector<boolean[]>();
|
||||
}
|
||||
|
||||
/* (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<int[]> 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<boolean[]> 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<int[]> 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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<double[]> vectorOfSourceTimeSeries;
|
||||
|
||||
/**
|
||||
* Storage for destination observations supplied via {@link #addObservations(double[], double[])} etc.
|
||||
*/
|
||||
protected Vector<double[]> vectorOfDestinationTimeSeries;
|
||||
|
||||
/**
|
||||
* Storage for validity arrays for supplied source observations.
|
||||
* Entries are null where the whole corresponding observation time-series is valid
|
||||
*/
|
||||
protected Vector<boolean[]> vectorOfValidityOfSource;
|
||||
|
||||
/**
|
||||
* Storage for validity arrays for supplied destination observations.
|
||||
* Entries are null where the whole corresponding observation time-series is valid
|
||||
*/
|
||||
protected Vector<boolean[]> 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<double[]>();
|
||||
vectorOfDestinationTimeSeries = new Vector<double[]>();
|
||||
vectorOfValidityOfSource = new Vector<boolean[]>();
|
||||
vectorOfValidityOfDestination = new Vector<boolean[]>();
|
||||
}
|
||||
|
||||
@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<int[]> 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<double[]> destIterator = vectorOfDestinationTimeSeries.iterator();
|
||||
Iterator<boolean[]> sourceValidityIterator = vectorOfValidityOfSource.iterator();
|
||||
Iterator<boolean[]> 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<int[]> 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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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})</li>
|
||||
* {@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.</li>
|
||||
* <li>{@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</li>
|
||||
|
|
|
|||
|
|
@ -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}.</li>
|
||||
* 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).</li>
|
||||
* </li>
|
||||
* <li>Computed values are in <b>nats</b>, not bits!</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
|
|
@ -73,6 +79,8 @@ import infodynamics.measures.continuous.TransferEntropyCalculatorViaCondMutualIn
|
|||
* <a href="http://dx.doi.org/10.1103/PhysRevE.77.026110">
|
||||
* "Local information transfer as a spatiotemporal filter for complex systems"</a>
|
||||
* Physical Review E 77, 026110, 2008.</li>
|
||||
* <li>Ragwitz and Kantz, "Markov models from data by simple nonlinear time series
|
||||
* predictors in delay embedding spaces", Physical Review E, vol 65, 056201 (2002).</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Joseph Lizier (<a href="joseph.lizier at gmail.com">email</a>,
|
||||
|
|
@ -108,6 +116,71 @@ public class TransferEntropyCalculatorKraskov
|
|||
*/
|
||||
protected Hashtable<String,String> 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:</p>
|
||||
* <ul>
|
||||
* <li>{@link #PROP_KRASKOV_ALG_NUM} -- which Kraskov algorithm number to use (1 or 2).</li>
|
||||
* <li>{@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.</li>
|
||||
* <li>{@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</li>
|
||||
* <li>{@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</li>
|
||||
* <li>{@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}</li>
|
||||
* <li>Any properties accepted by {@link TransferEntropyCalculatorViaCondMutualInfo#setProperty(String, String)}</li>
|
||||
* <li>Or properties accepted by the underlying
|
||||
* {@link ConditionalMutualInfoCalculatorMultiVariateKraskov#setProperty(String, String)} implementation.</li>
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue