mirror of https://github.com/jlizier/jidt
Enabled auto-embedding for TE Gaussian. Did so by bringing up auto-embedding for TE functionality up from the KSG estimator to the via Conditional MI class. Also added new property to Gaussian TE for number of surrogates to use for bias correction in embedding (if not using analytic bias correction), like Gaussian AIS. This also necessitated adding an empty preFinaliseAddObservations() method to the TE Gaussian multivariate estimator, to ensure it did not yet try to autoembed until that is enabled in the multivariate calculator. Unit tests included here as well (included using more samples for TE KSG autoembedding to ensure we get the correct answer more reliably -- should probably add a stronger effect for that too).
This commit is contained in:
parent
efb8243ed7
commit
a34bce25ba
|
@ -594,7 +594,7 @@ public class ActiveInfoStorageCalculatorViaMutualInfo implements
|
|||
|
||||
/**
|
||||
* Internal method to compute any additional bias correction in the underlying calculator
|
||||
* during auto-embedding in preFinaliseObservations if required.
|
||||
* during auto-embedding in {@link #preFinaliseAddObservations()} if required.
|
||||
*
|
||||
* @return additional bias correction to remove (will be zero if assumed to be already bias corrected).
|
||||
* @throws Exception
|
||||
|
|
|
@ -18,9 +18,18 @@
|
|||
|
||||
package infodynamics.measures.continuous;
|
||||
|
||||
import infodynamics.measures.continuous.gaussian.ActiveInfoStorageCalculatorGaussian;
|
||||
import infodynamics.measures.continuous.gaussian.ConditionalMutualInfoCalculatorMultiVariateGaussian;
|
||||
import infodynamics.measures.continuous.gaussian.TransferEntropyCalculatorGaussian;
|
||||
import infodynamics.measures.continuous.kraskov.ActiveInfoStorageCalculatorKraskov;
|
||||
import infodynamics.measures.continuous.kraskov.ConditionalMutualInfoCalculatorMultiVariateKraskov;
|
||||
import infodynamics.measures.continuous.kraskov.ConditionalMutualInfoCalculatorMultiVariateKraskov1;
|
||||
import infodynamics.measures.continuous.kraskov.ConditionalMutualInfoCalculatorMultiVariateKraskov2;
|
||||
import infodynamics.measures.continuous.kraskov.MutualInfoCalculatorMultiVariateKraskov;
|
||||
import infodynamics.utils.EmpiricalMeasurementDistribution;
|
||||
import infodynamics.utils.MatrixUtils;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.Vector;
|
||||
|
||||
|
@ -45,6 +54,15 @@ import java.util.Vector;
|
|||
* <li>{@link infodynamics.measures.continuous.kraskov.TransferEntropyCalculatorKraskov}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>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},
|
||||
* or as per the max. bias-corrected AIS criteria by
|
||||
* setting the property {@link #PROP_AUTO_EMBED_METHOD} to {@link #AUTO_EMBED_METHOD_MAX_CORR_AIS}
|
||||
* (as per Garland et al. in the reference list)
|
||||
* plus additional parameter settings for these.
|
||||
* </p>
|
||||
*
|
||||
* TODO Delete TransferEntropyCalculatorCommon once we've switched everything over to use this?
|
||||
* Might be useful to leave it after all, and move common functionality from here to there.
|
||||
*
|
||||
|
@ -57,6 +75,11 @@ import java.util.Vector;
|
|||
* <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>
|
||||
* <li>J. Garland, R. G. James, E. Bradley, <a href="http://dx.doi.org/10.1103/physreve.93.022221">
|
||||
* "Leveraging information storage to select forecast-optimal parameters for delay-coordinate reconstructions"</a>,
|
||||
* Physical Review E, Vol. 93 (2016), 022221, doi:</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Joseph Lizier, <a href="joseph.lizier at gmail.com">email</a>,
|
||||
|
@ -132,6 +155,99 @@ public class TransferEntropyCalculatorViaCondMutualInfo implements
|
|||
*/
|
||||
protected int[] separateNumObservations;
|
||||
|
||||
/**
|
||||
* Property name for specifying which (if any) auto-embedding method to use.
|
||||
* Valid values include {@link #AUTO_EMBED_METHOD_RAGWITZ}, {@link #AUTO_EMBED_METHOD_RAGWITZ_DEST_ONLY},
|
||||
* {@link #AUTO_EMBED_METHOD_MAX_CORR_AIS}, {@link #AUTO_EMBED_METHOD_MAX_CORR_AIS_DEST_ONLY},
|
||||
* {@link #AUTO_EMBED_METHOD_MAX_CORR_AIS_AND_TE} and {@link #AUTO_EMBED_METHOD_NONE}.
|
||||
* 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";
|
||||
/**
|
||||
* Valid value for the property {@link #PROP_AUTO_EMBED_METHOD} indicating that
|
||||
* the automatic embedding should be done by maximising the bias corrected
|
||||
* AIS, for both source and destination time series
|
||||
*/
|
||||
public static final String AUTO_EMBED_METHOD_MAX_CORR_AIS = "MAX_CORR_AIS";
|
||||
/**
|
||||
* Valid value for the property {@link #PROP_AUTO_EMBED_METHOD} indicating that
|
||||
* the automatic embedding should be done by maximising the bias corrected
|
||||
* AIS for the target and subsequently maximising the TE over source embeddings,
|
||||
* given a fixed source-target delay.
|
||||
*/
|
||||
public static final String AUTO_EMBED_METHOD_MAX_CORR_AIS_AND_TE = "MAX_CORR_AIS_AND_TE";
|
||||
/**
|
||||
* Valid value for the property {@link #PROP_AUTO_EMBED_METHOD} indicating that
|
||||
* the automatic embedding should be done by maximising the bias corrected
|
||||
* AIS, for destination time series only
|
||||
*/
|
||||
public static final String AUTO_EMBED_METHOD_MAX_CORR_AIS_DEST_ONLY = "MAX_CORR_AIS_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;
|
||||
|
||||
/**
|
||||
* Storage for the properties ready to pass onto the underlying conditional MI calculators should they change
|
||||
*/
|
||||
protected Hashtable<String,String> props = new Hashtable<String,String>();
|
||||
|
||||
/**
|
||||
* Construct a transfer entropy calculator using an instance of
|
||||
* condMiCalculatorClassName as the underlying conditional mutual information calculator.
|
||||
|
@ -269,6 +385,34 @@ public class TransferEntropyCalculatorViaCondMutualInfo implements
|
|||
* <p>Valid property names, and what their
|
||||
* values should represent, include:</p>
|
||||
* <ul>
|
||||
* <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;
|
||||
* {@link #AUTO_EMBED_METHOD_MAX_CORR_AIS} for use of the max bias corrected AIS criteria
|
||||
* for both source and destination (searching up to {@link #PROP_K_SEARCH_MAX} and
|
||||
* {@link #PROP_TAU_SEARCH_MAX}), {@link #AUTO_EMBED_METHOD_MAX_CORR_AIS_DEST_ONLY} for use of
|
||||
* this criteria for the destination only and {@link #AUTO_EMBED_METHOD_MAX_CORR_AIS_AND_TE} for
|
||||
* use of this criteria for the target, plus the max bias corrected TE for source embeddings.
|
||||
* 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 TransferEntropyCalculator#setProperty(String, String)}</li>
|
||||
* <li>Or properties accepted by the underlying
|
||||
* {@link ConditionalMutualInfoCalculatorMultiVariate#setProperty(String, String)} implementation.</li>
|
||||
|
@ -293,10 +437,24 @@ public class TransferEntropyCalculatorViaCondMutualInfo implements
|
|||
l_tau = Integer.parseInt(propertyValue);
|
||||
} else if (propertyName.equalsIgnoreCase(DELAY_PROP_NAME)) {
|
||||
delay = Integer.parseInt(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 {
|
||||
// No property was set on this class, assume it is for the underlying
|
||||
// conditional MI calculator
|
||||
condMiCalc.setProperty(propertyName, propertyValue);
|
||||
props.put(propertyName, propertyValue);
|
||||
propertySet = false;
|
||||
}
|
||||
if (debug && propertySet) {
|
||||
|
@ -317,6 +475,18 @@ public class TransferEntropyCalculatorViaCondMutualInfo implements
|
|||
return Integer.toString(l_tau);
|
||||
} else if (propertyName.equalsIgnoreCase(DELAY_PROP_NAME)) {
|
||||
return Integer.toString(delay);
|
||||
} 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 {
|
||||
// No property matches for this class, assume it is for the underlying
|
||||
// conditional MI calculator
|
||||
|
@ -498,9 +668,168 @@ public class TransferEntropyCalculatorViaCondMutualInfo implements
|
|||
* if no new functionality is required.
|
||||
*/
|
||||
protected void preFinaliseAddObservations() throws Exception {
|
||||
// Empty implementation supplied by default.
|
||||
// Automatically determine the embedding parameters for the given time series
|
||||
|
||||
if (autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_NONE)) {
|
||||
return;
|
||||
}
|
||||
// Else we need to auto embed
|
||||
|
||||
// Check user has set a valid embedding method:
|
||||
if (!(autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_RAGWITZ) ||
|
||||
autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_RAGWITZ_DEST_ONLY) ||
|
||||
autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_MAX_CORR_AIS) ||
|
||||
autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_MAX_CORR_AIS_DEST_ONLY) ||
|
||||
autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_MAX_CORR_AIS_AND_TE))) {
|
||||
throw new Exception("Invalid auto-embed method: " + autoEmbeddingMethod);
|
||||
}
|
||||
|
||||
// Use an AIS calculator to embed both time-series individually:
|
||||
ActiveInfoStorageCalculator aisCalc;
|
||||
if (autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_RAGWITZ) ||
|
||||
autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_RAGWITZ_DEST_ONLY)) {
|
||||
// We're doing Ragwitz auto-embedding:
|
||||
// Use a KSG estimator, as Ragwitz is easy with these
|
||||
aisCalc = new ActiveInfoStorageCalculatorKraskov();
|
||||
} else {
|
||||
// We're doing max bias-corrected AIS embedding, grab an instance of
|
||||
// the corresponding calculator for the estimator type.
|
||||
// This is not as nicely object-oriented as I would like, but I can't attach an
|
||||
// to this superclass to grab a relevant AIS calculator without making it abstract,
|
||||
// and I didn't want this class to be abstract.
|
||||
if (condMiCalc instanceof ConditionalMutualInfoCalculatorMultiVariateGaussian) {
|
||||
aisCalc = new ActiveInfoStorageCalculatorGaussian();
|
||||
String numCorrectingSurrogates = getProperty(TransferEntropyCalculatorGaussian.PROP_MAX_CORR_NUM_SURROGATES);
|
||||
if (numCorrectingSurrogates != null) {
|
||||
aisCalc.setProperty(
|
||||
ActiveInfoStorageCalculatorGaussian.PROP_MAX_CORR_AIS_NUM_SURROGATES,
|
||||
numCorrectingSurrogates);
|
||||
}
|
||||
} else if (condMiCalc instanceof ConditionalMutualInfoCalculatorMultiVariateKraskov1) {
|
||||
aisCalc = new ActiveInfoStorageCalculatorKraskov(1);
|
||||
} else if (condMiCalc instanceof ConditionalMutualInfoCalculatorMultiVariateKraskov2) {
|
||||
aisCalc = new ActiveInfoStorageCalculatorKraskov(2);
|
||||
// Add these lines in once we have a CMI kernel calculator:
|
||||
// } else if (condMiCalc instanceof ConditionalMutualInfoCalculatorMultiVariateKernel) {
|
||||
// aisCalc = new ActiveInfoStorageCalculatorKernel();
|
||||
} else {
|
||||
throw new RuntimeException("Invalid CMI type found during auto-embedding: " + condMiCalc.getClass().getName());
|
||||
}
|
||||
}
|
||||
// Set the properties for the underlying MI calculator here to match our
|
||||
// properties for our underlying CMI calculator:
|
||||
for (String key : props.keySet()) {
|
||||
aisCalc.setProperty(key, props.get(key));
|
||||
}
|
||||
// Set the auto-embedding properties as we require:
|
||||
if (autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_RAGWITZ) ||
|
||||
autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_RAGWITZ_DEST_ONLY)) {
|
||||
// We're doing Ragwitz auto-embedding
|
||||
aisCalc.setProperty(ActiveInfoStorageCalculatorViaMutualInfo.PROP_AUTO_EMBED_METHOD,
|
||||
ActiveInfoStorageCalculatorViaMutualInfo.AUTO_EMBED_METHOD_RAGWITZ);
|
||||
// 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(ActiveInfoStorageCalculatorViaMutualInfo.PROP_RAGWITZ_NUM_NNS,
|
||||
getProperty(PROP_RAGWITZ_NUM_NNS));
|
||||
} else {
|
||||
// We're doing max bias-corrected AIS embedding:
|
||||
aisCalc.setProperty(ActiveInfoStorageCalculatorViaMutualInfo.PROP_AUTO_EMBED_METHOD,
|
||||
ActiveInfoStorageCalculatorViaMutualInfo.AUTO_EMBED_METHOD_MAX_CORR_AIS);
|
||||
}
|
||||
aisCalc.setProperty(ActiveInfoStorageCalculatorViaMutualInfo.PROP_K_SEARCH_MAX,
|
||||
Integer.toString(k_search_max));
|
||||
aisCalc.setProperty(ActiveInfoStorageCalculatorViaMutualInfo.PROP_TAU_SEARCH_MAX,
|
||||
Integer.toString(tau_search_max));
|
||||
|
||||
// Embed the destination:
|
||||
if (debug) {
|
||||
System.out.println("Starting embedding of destination:");
|
||||
}
|
||||
prepareAISCalculator(aisCalc, vectorOfDestinationTimeSeries, vectorOfValidityOfDestination);
|
||||
// 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) ||
|
||||
autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_MAX_CORR_AIS)) {
|
||||
// Embed the source also:
|
||||
if (debug) {
|
||||
System.out.println("Starting embedding of source:");
|
||||
}
|
||||
prepareAISCalculator(aisCalc, vectorOfSourceTimeSeries, vectorOfValidityOfSource);
|
||||
// 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);
|
||||
}
|
||||
|
||||
} else if (autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_MAX_CORR_AIS_AND_TE)) {
|
||||
if (debug) {
|
||||
System.out.println("Starting embedding of source:");
|
||||
}
|
||||
|
||||
double bestTE = Double.NEGATIVE_INFINITY;
|
||||
int l_candidate_best = 1;
|
||||
int l_tau_candidate_best = 1;
|
||||
|
||||
// Iterate over all possible source embeddings
|
||||
for (int l_candidate = 1; l_candidate <= k_search_max; l_candidate++) {
|
||||
for (int l_tau_candidate = 1; l_tau_candidate <= tau_search_max; l_tau_candidate++) {
|
||||
|
||||
// Use our internal CMI calculator in case it has any particular
|
||||
// properties we need to have been set already
|
||||
prepareCMICalculator(condMiCalc, k, k_tau, l_candidate, l_tau_candidate, delay);
|
||||
double thisTE = condMiCalc.computeAverageLocalOfObservations();
|
||||
thisTE -= computeAdditionalBiasToRemove();
|
||||
|
||||
if (debug) {
|
||||
System.out.printf("TE for l=%d, l_tau=%d is %.3f\n",
|
||||
l_candidate, l_tau_candidate, thisTE);
|
||||
}
|
||||
|
||||
if (thisTE > bestTE) {
|
||||
// This parameter setting is the best so far:
|
||||
bestTE = thisTE;
|
||||
l_candidate_best = l_candidate;
|
||||
l_tau_candidate_best = l_tau_candidate;
|
||||
}
|
||||
if (l_candidate == 1) {
|
||||
// tau is irrelevant, so no point testing other values
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
l = l_candidate_best;
|
||||
l_tau = l_tau_candidate_best;
|
||||
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:
|
||||
startTimeForFirstDestEmbedding =
|
||||
computeStartTimeForFirstDestEmbedding(k, k_tau, l, l_tau, delay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to compute any additional bias correction in the underlying calculator
|
||||
* during auto-embedding in {@link #preFinaliseAddObservations()} if required.
|
||||
*
|
||||
* @return additional bias correction to remove (will be zero if assumed to be already bias corrected).
|
||||
* @throws Exception
|
||||
*/
|
||||
protected double computeAdditionalBiasToRemove() throws Exception {
|
||||
// Default implementation does nothing
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finaliseAddObservations() throws Exception {
|
||||
// Auto embed if required
|
||||
|
@ -514,6 +843,34 @@ public class TransferEntropyCalculatorViaCondMutualInfo implements
|
|||
vectorOfValidityOfDestination = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the given pre-instantiated (and properties supplied)
|
||||
* Active information storage calculator with the given data set,
|
||||
* for a calculation of auto-embedding parameters.
|
||||
*
|
||||
* @param aisCalc_in_use AIS calculator to supply
|
||||
* @param setOfTimeSeriesSamples set of times series samples for the calculation
|
||||
* @param setOfValidities set of time series of validity indications. Each can be a null array if all are valid
|
||||
* @throws Exception
|
||||
*/
|
||||
protected static void prepareAISCalculator(ActiveInfoStorageCalculator aisCalc,
|
||||
Vector<double[]> setOfTimeSeriesSamples, Vector<boolean[]> setOfValidities)
|
||||
throws Exception {
|
||||
|
||||
aisCalc.initialise();
|
||||
aisCalc.startAddObservations();
|
||||
Iterator<boolean[]> validityIterator = setOfValidities.iterator();
|
||||
for (double[] timeSeries : setOfTimeSeriesSamples) {
|
||||
boolean[] validity = validityIterator.next();
|
||||
if (validity == null) {
|
||||
aisCalc.addObservations(timeSeries);
|
||||
} else {
|
||||
aisCalc.addObservations(timeSeries, validity);
|
||||
}
|
||||
}
|
||||
aisCalc.finaliseAddObservations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the given pre-instantiated (and properties supplied)
|
||||
* Conditional mutual information calculator with this data set,
|
||||
|
|
|
@ -22,6 +22,7 @@ import infodynamics.measures.continuous.TransferEntropyCalculator;
|
|||
import infodynamics.measures.continuous.TransferEntropyCalculatorViaCondMutualInfo;
|
||||
import infodynamics.utils.AnalyticNullDistributionComputer;
|
||||
import infodynamics.utils.ChiSquareMeasurementDistribution;
|
||||
import infodynamics.utils.EmpiricalMeasurementDistribution;
|
||||
|
||||
/**
|
||||
* <p>Computes the differential transfer entropy (TE) between two univariate
|
||||
|
@ -91,6 +92,20 @@ public class TransferEntropyCalculatorGaussian
|
|||
*/
|
||||
public static final String COND_MI_CALCULATOR_GAUSSIAN = ConditionalMutualInfoCalculatorMultiVariateGaussian.class.getName();
|
||||
|
||||
/**
|
||||
* Property name for the number of surrogates to use in computing the bias correction
|
||||
* if required for the auto embedding method in {@link TransferEntropyCalculatorViaCondMutualInfo}.
|
||||
* Defaults to 0 meaning that we use analytic bias correction rather than empirical
|
||||
* surrogates. Note: This is not used for bias correction of the raw values, only for auto-embedding
|
||||
*/
|
||||
public static final String PROP_MAX_CORR_NUM_SURROGATES = "AUTO_EMBED_MAX_CORR_SURROGATES";
|
||||
/**
|
||||
* Internal variable for storing the number of surrogates to use for the
|
||||
* auto-embedding in {@link TransferEntropyCalculatorViaCondMutualInfo}.
|
||||
* 0 mean we use analytic approaches rather than surrogates.
|
||||
*/
|
||||
protected int auto_embed_num_surrogates = 0;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the Gaussian-estimate style transfer entropy calculator
|
||||
*
|
||||
|
@ -124,6 +139,78 @@ public class TransferEntropyCalculatorGaussian
|
|||
setCovariance(covariance, numObservations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets properties for the TE Gaussian calculator.
|
||||
* New property values are not guaranteed to take effect until the next call
|
||||
* to an initialise method.
|
||||
*
|
||||
* <p>Valid property names, and what their
|
||||
* values should represent, include:</p>
|
||||
* <ul>
|
||||
* <li>{@link #PROP_MAX_CORR_NUM_SURROGATES} -- number of surrogates to use
|
||||
* to compute the bias correction
|
||||
* in the auto-embedding if the property {@link #PROP_AUTO_EMBED_METHOD}
|
||||
* has been set to one of the bias-corrected maximisation methods. Defaults to 0
|
||||
* meaning that we use analytic bias correction.
|
||||
* Note: this is not used for other bias-correction, only inside auto-embedding</li>
|
||||
* <li>Any properties accepted by {@link super#setProperty(String, String)}</li>
|
||||
* <li>Or properties accepted by the underlying
|
||||
* {@link MutualInfoCalculatorMultiVariateGaussian#setProperty(String, String)} implementation.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param propertyName name of the property
|
||||
* @param propertyValue value of the property.
|
||||
* @throws Exception if there is a problem with the supplied value).
|
||||
*/
|
||||
@Override
|
||||
public void setProperty(String propertyName, String propertyValue)
|
||||
throws Exception {
|
||||
boolean propertySet = true;
|
||||
if (propertyName.equalsIgnoreCase(PROP_MAX_CORR_NUM_SURROGATES)) {
|
||||
auto_embed_num_surrogates = Integer.parseInt(propertyValue);
|
||||
} else {
|
||||
propertySet = false;
|
||||
// Assume it was a property for the parent class or underlying MI calculator
|
||||
super.setProperty(propertyName, propertyValue);
|
||||
}
|
||||
if (debug && propertySet) {
|
||||
System.out.println(this.getClass().getSimpleName() + ": Set property " + propertyName +
|
||||
" to " + propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String propertyName)
|
||||
throws Exception {
|
||||
|
||||
if (propertyName.equalsIgnoreCase(PROP_MAX_CORR_NUM_SURROGATES)) {
|
||||
return Integer.toString(auto_embed_num_surrogates);
|
||||
} else {
|
||||
// Assume it was a property for the parent class or underlying MI calculator
|
||||
return super.getProperty(propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double computeAdditionalBiasToRemove() throws Exception {
|
||||
boolean biasCorrected = Boolean.getBoolean(getProperty(ConditionalMutualInfoCalculatorMultiVariateGaussian.PROP_BIAS_CORRECTION));
|
||||
if (auto_embed_num_surrogates == 0) {
|
||||
// Analytic bias correction:
|
||||
if (!biasCorrected) {
|
||||
ChiSquareMeasurementDistribution analyticMeasDist =
|
||||
((ConditionalMutualInfoCalculatorMultiVariateGaussian)condMiCalc).computeSignificance();
|
||||
return analyticMeasDist.getMeanOfDistribution();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// Empirical bias correction with auto_embed_num_surrogates surrogates:
|
||||
EmpiricalMeasurementDistribution measDist =
|
||||
condMiCalc.computeSignificance(auto_embed_num_surrogates);
|
||||
return measDist.getMeanOfDistribution();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an <b>analytic</b> distribution of what the TE would look like,
|
||||
* under a null hypothesis that our variables had no relation
|
||||
|
|
|
@ -155,4 +155,11 @@ public class TransferEntropyCalculatorMultiVariateGaussian
|
|||
throws Exception {
|
||||
return ((ConditionalMutualInfoCalculatorMultiVariateGaussian) condMiCalc).computeSignificance();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preFinaliseAddObservations() throws Exception {
|
||||
// TODO Remove this once auto-embedding is completed for multivariate TE.
|
||||
// At the moment this empty method ensures that the auto-embedding in the univariate
|
||||
// class does not get applied here.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,11 +18,6 @@
|
|||
|
||||
package infodynamics.measures.continuous.kraskov;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.Vector;
|
||||
|
||||
import infodynamics.measures.continuous.ActiveInfoStorageCalculator;
|
||||
import infodynamics.measures.continuous.ConditionalMutualInfoCalculatorMultiVariate;
|
||||
import infodynamics.measures.continuous.TransferEntropyCalculator;
|
||||
import infodynamics.measures.continuous.TransferEntropyCalculatorViaCondMutualInfo;
|
||||
|
@ -53,13 +48,8 @@ import infodynamics.measures.continuous.TransferEntropyCalculatorViaCondMutualIn
|
|||
* as outlined
|
||||
* in {@link TransferEntropyCalculatorViaCondMutualInfo#setProperty(String, String)});
|
||||
* 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},
|
||||
* or as per the max. bias-corrected AIS criteria by
|
||||
* setting the property {@link #PROP_AUTO_EMBED_METHOD} to {@link #AUTO_EMBED_METHOD_MAX_CORR_AIS}
|
||||
* (as per Garland et al. in the reference list)
|
||||
* plus additional parameter settings for these.</li>
|
||||
* Embedding parameters may be automatically determined as outlined in
|
||||
* {@link TransferEntropyCalculatorViaCondMutualInfo#setProperty(String, String)}.</li>
|
||||
* </li>
|
||||
* <li>Computed values are in <b>nats</b>, not bits!</li>
|
||||
* </ul>
|
||||
|
@ -84,11 +74,6 @@ 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>
|
||||
* <li>J. Garland, R. G. James, E. Bradley, <a href="http://dx.doi.org/10.1103/physreve.93.022221">
|
||||
* "Leveraging information storage to select forecast-optimal parameters for delay-coordinate reconstructions"</a>,
|
||||
* Physical Review E, Vol. 93 (2016), 022221, doi:</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Joseph Lizier (<a href="joseph.lizier at gmail.com">email</a>,
|
||||
|
@ -119,98 +104,6 @@ public class TransferEntropyCalculatorKraskov
|
|||
*/
|
||||
protected int kraskovAlgorithmNumber = 1;
|
||||
protected boolean algChanged = false;
|
||||
/**
|
||||
* Storage for the properties ready to pass onto the underlying conditional MI calculators should they change
|
||||
*/
|
||||
protected Hashtable<String,String> props;
|
||||
|
||||
/**
|
||||
* Property name for specifying which (if any) auto-embedding method to use.
|
||||
* Valid values include {@link #AUTO_EMBED_METHOD_RAGWITZ}, {@link #AUTO_EMBED_METHOD_RAGWITZ_DEST_ONLY},
|
||||
* {@link #AUTO_EMBED_METHOD_MAX_CORR_AIS}, {@link #AUTO_EMBED_METHOD_MAX_CORR_AIS_DEST_ONLY},
|
||||
* {@link #AUTO_EMBED_METHOD_MAX_CORR_AIS_AND_TE} and {@link #AUTO_EMBED_METHOD_NONE}.
|
||||
* 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";
|
||||
/**
|
||||
* Valid value for the property {@link #PROP_AUTO_EMBED_METHOD} indicating that
|
||||
* the automatic embedding should be done by maximising the bias corrected
|
||||
* AIS, for both source and destination time series
|
||||
*/
|
||||
public static final String AUTO_EMBED_METHOD_MAX_CORR_AIS = "MAX_CORR_AIS";
|
||||
/**
|
||||
* Valid value for the property {@link #PROP_AUTO_EMBED_METHOD} indicating that
|
||||
* the automatic embedding should be done by maximising the bias corrected
|
||||
* AIS for the target and subsequently maximising the TE over source embeddings,
|
||||
* given a fixed source-target delay.
|
||||
*/
|
||||
public static final String AUTO_EMBED_METHOD_MAX_CORR_AIS_AND_TE = "MAX_CORR_AIS_AND_TE";
|
||||
/**
|
||||
* Valid value for the property {@link #PROP_AUTO_EMBED_METHOD} indicating that
|
||||
* the automatic embedding should be done by maximising the bias corrected
|
||||
* AIS, for destination time series only
|
||||
*/
|
||||
public static final String AUTO_EMBED_METHOD_MAX_CORR_AIS_DEST_ONLY = "MAX_CORR_AIS_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
|
||||
|
@ -225,7 +118,6 @@ public class TransferEntropyCalculatorKraskov
|
|||
public TransferEntropyCalculatorKraskov() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
|
||||
super(COND_MI_CALCULATOR_KRASKOV1);
|
||||
kraskovAlgorithmNumber = 1;
|
||||
props = new Hashtable<String,String>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -249,7 +141,6 @@ public class TransferEntropyCalculatorKraskov
|
|||
} else {
|
||||
throw new ClassNotFoundException("Must be an underlying Kraskov-Grassberger conditional MI calculator");
|
||||
}
|
||||
props = new Hashtable<String,String>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -268,7 +159,6 @@ public class TransferEntropyCalculatorKraskov
|
|||
if ((algorithm != 1) && (algorithm != 2)) {
|
||||
throw new ClassNotFoundException("Algorithm must be 1 or 2");
|
||||
}
|
||||
props = new Hashtable<String,String>();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -308,34 +198,6 @@ 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;
|
||||
* {@link #AUTO_EMBED_METHOD_MAX_CORR_AIS} for use of the max bias corrected AIS criteria
|
||||
* for both source and destination (searching up to {@link #PROP_K_SEARCH_MAX} and
|
||||
* {@link #PROP_TAU_SEARCH_MAX}), {@link #AUTO_EMBED_METHOD_MAX_CORR_AIS_DEST_ONLY} for use of
|
||||
* this criteria for the destination only and {@link #AUTO_EMBED_METHOD_MAX_CORR_AIS_AND_TE} for
|
||||
* use of this criteria for the target, plus the max bias corrected TE for source embeddings.
|
||||
* 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>
|
||||
|
@ -364,23 +226,9 @@ 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);
|
||||
props.put(propertyName, propertyValue); // This will keep properties for the super class as well as the cond MI calculator, but this is ok
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,169 +236,9 @@ 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) ||
|
||||
autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_MAX_CORR_AIS) ||
|
||||
autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_MAX_CORR_AIS_DEST_ONLY) ||
|
||||
autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_MAX_CORR_AIS_AND_TE)) {
|
||||
|
||||
// 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:
|
||||
if (autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_RAGWITZ) ||
|
||||
autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_RAGWITZ_DEST_ONLY)) {
|
||||
// We're doing Ragwitz auto-embedding
|
||||
aisCalc.setProperty(ActiveInfoStorageCalculatorKraskov.PROP_AUTO_EMBED_METHOD,
|
||||
ActiveInfoStorageCalculatorKraskov.AUTO_EMBED_METHOD_RAGWITZ);
|
||||
// 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));
|
||||
} else {
|
||||
// We're doing max bias-corrected AIS embeding:
|
||||
aisCalc.setProperty(ActiveInfoStorageCalculatorKraskov.PROP_AUTO_EMBED_METHOD,
|
||||
ActiveInfoStorageCalculatorKraskov.AUTO_EMBED_METHOD_MAX_CORR_AIS);
|
||||
}
|
||||
aisCalc.setProperty(ActiveInfoStorageCalculatorKraskov.PROP_K_SEARCH_MAX,
|
||||
Integer.toString(k_search_max));
|
||||
aisCalc.setProperty(ActiveInfoStorageCalculatorKraskov.PROP_TAU_SEARCH_MAX,
|
||||
Integer.toString(tau_search_max));
|
||||
|
||||
// Embed the destination:
|
||||
if (debug) {
|
||||
System.out.println("Starting embedding of destination:");
|
||||
}
|
||||
prepareAISCalculator(aisCalc, vectorOfDestinationTimeSeries, vectorOfValidityOfDestination);
|
||||
// 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) ||
|
||||
autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_MAX_CORR_AIS)) {
|
||||
// Embed the source also:
|
||||
if (debug) {
|
||||
System.out.println("Starting embedding of source:");
|
||||
}
|
||||
prepareAISCalculator(aisCalc, vectorOfSourceTimeSeries, vectorOfValidityOfSource);
|
||||
// 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);
|
||||
}
|
||||
|
||||
} else if (autoEmbeddingMethod.equalsIgnoreCase(AUTO_EMBED_METHOD_MAX_CORR_AIS_AND_TE)) {
|
||||
if (debug) {
|
||||
System.out.println("Starting embedding of source:");
|
||||
}
|
||||
|
||||
double bestTE = Double.NEGATIVE_INFINITY;
|
||||
int l_candidate_best = 1;
|
||||
int l_tau_candidate_best = 1;
|
||||
|
||||
// Iterate over all possible embeddings
|
||||
for (int l_candidate = 1; l_candidate <= k_search_max; l_candidate++) {
|
||||
for (int l_tau_candidate = 1; l_tau_candidate <= tau_search_max; l_tau_candidate++) {
|
||||
|
||||
// Use our internal CMI calculator in case it has any particular
|
||||
// properties we need to have been set already
|
||||
prepareCMICalculator(condMiCalc, k, k_tau, l_candidate, l_tau_candidate, delay);
|
||||
double thisTE = condMiCalc.computeAverageLocalOfObservations();
|
||||
|
||||
if (debug) {
|
||||
System.out.printf("TE for l=%d, l_tau=%d is %.3f\n",
|
||||
l_candidate, l_tau_candidate, thisTE);
|
||||
}
|
||||
|
||||
if (thisTE > bestTE) {
|
||||
// This parameter setting is the best so far:
|
||||
bestTE = thisTE;
|
||||
l_candidate_best = l_candidate;
|
||||
l_tau_candidate_best = l_tau_candidate;
|
||||
}
|
||||
if (l_candidate == 1) {
|
||||
// tau is irrelevant, so no point testing other values
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
l = l_candidate_best;
|
||||
l_tau = l_tau_candidate_best;
|
||||
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:
|
||||
startTimeForFirstDestEmbedding =
|
||||
computeStartTimeForFirstDestEmbedding(k, k_tau, l, l_tau, delay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the given pre-instantiated (and properties supplied)
|
||||
* Active information storage calculator with the given data set,
|
||||
* for a calculation of auto-embedding parameters.
|
||||
*
|
||||
* @param aisCalc_in_use AIS calculator to supply
|
||||
* @param setOfTimeSeriesSamples set of times series samples for the calculation
|
||||
* @param setOfValidities set of time series of validity indications. Each can be a null array if all are valid
|
||||
* @throws Exception
|
||||
*/
|
||||
protected static void prepareAISCalculator(ActiveInfoStorageCalculator aisCalc,
|
||||
Vector<double[]> setOfTimeSeriesSamples, Vector<boolean[]> setOfValidities)
|
||||
throws Exception {
|
||||
|
||||
aisCalc.initialise();
|
||||
aisCalc.startAddObservations();
|
||||
Iterator<boolean[]> validityIterator = setOfValidities.iterator();
|
||||
for (double[] timeSeries : setOfTimeSeriesSamples) {
|
||||
boolean[] validity = validityIterator.next();
|
||||
if (validity == null) {
|
||||
aisCalc.addObservations(timeSeries);
|
||||
} else {
|
||||
aisCalc.addObservations(timeSeries, validity);
|
||||
}
|
||||
}
|
||||
aisCalc.finaliseAddObservations();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,10 +18,12 @@
|
|||
|
||||
package infodynamics.measures.continuous.gaussian;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.Vector;
|
||||
|
||||
import infodynamics.measures.continuous.TransferEntropyAbstractTester;
|
||||
import infodynamics.measures.continuous.TransferEntropyCalculatorViaCondMutualInfo;
|
||||
import infodynamics.measures.continuous.kraskov.TransferEntropyCalculatorKraskov;
|
||||
import infodynamics.utils.ArrayFileReader;
|
||||
import infodynamics.utils.MatrixUtils;
|
||||
import infodynamics.utils.RandomGenerator;
|
||||
|
@ -409,4 +411,121 @@ public class TransferEntropyGaussianTester extends TransferEntropyAbstractTester
|
|||
}
|
||||
return startAndEndTimePairs;
|
||||
}
|
||||
|
||||
public void testAutoEmbeddingAIS() throws Exception {
|
||||
System.out.println("Start AIS autoembedding test.");
|
||||
// Generate multivariate data
|
||||
RandomGenerator rg = new RandomGenerator();
|
||||
double[] source = rg.generateNormalData(5000, 0, 1);
|
||||
double[] target = rg.generateNormalData(5000, 0, 1);
|
||||
|
||||
for (int i=3; i < source.length; i++) {
|
||||
source[i] = 0.2*source[i-3] + 0.2*source[i-2] + 0.2*source[i-1] + source[i];
|
||||
target[i] = 0.2*target[i-3] + 0.2*target[i-2] + 0.2*target[i-1] + target[i];
|
||||
}
|
||||
|
||||
int correctK = 3;
|
||||
int correctL = 3;
|
||||
|
||||
// Instantiate calculator and set search bounds
|
||||
TransferEntropyCalculatorGaussian teCalc =
|
||||
new TransferEntropyCalculatorGaussian();
|
||||
teCalc.setProperty("k", "4");
|
||||
teCalc.setProperty(teCalc.PROP_K_SEARCH_MAX, "3");
|
||||
teCalc.setProperty(teCalc.PROP_TAU_SEARCH_MAX, "1");
|
||||
teCalc.setProperty(teCalc.PROP_AUTO_EMBED_METHOD, teCalc.AUTO_EMBED_METHOD_MAX_CORR_AIS);
|
||||
teCalc.setDebug(true);
|
||||
|
||||
// Run optimisation
|
||||
teCalc.initialise();
|
||||
teCalc.setObservations(source, target);
|
||||
int optimisedK = Integer.parseInt(teCalc.getProperty(TransferEntropyCalculatorKraskov.K_PROP_NAME));
|
||||
int optimisedL = Integer.parseInt(teCalc.getProperty(TransferEntropyCalculatorKraskov.L_PROP_NAME));
|
||||
|
||||
// Test that answer was correct
|
||||
assertEquals(correctK, optimisedK);
|
||||
assertEquals(correctL, optimisedL);
|
||||
}
|
||||
|
||||
public void testAutoEmbeddingTE() throws Exception {
|
||||
System.out.println("Start AIS+TE autoembedding test.");
|
||||
|
||||
// Generate multivariate data (note that source time series has no memory)
|
||||
RandomGenerator rg = new RandomGenerator();
|
||||
double[] source = rg.generateNormalData(10000, 0, 1);
|
||||
double[] target = rg.generateNormalData(10000, 0, 1);
|
||||
|
||||
for (int i=3; i < source.length; i++) {
|
||||
target[i] = 0.2*source[i-2] + 0.2*source[i-1] +
|
||||
0.2*target[i-2] + 0.2*target[i-1] + target[i];
|
||||
}
|
||||
|
||||
int correctK = 2;
|
||||
int correctL = 2;
|
||||
|
||||
// Instantiate calculator and set search bounds
|
||||
TransferEntropyCalculatorGaussian teCalc =
|
||||
new TransferEntropyCalculatorGaussian();
|
||||
teCalc.setProperty("k", "4");
|
||||
teCalc.setProperty(teCalc.PROP_K_SEARCH_MAX, "2");
|
||||
teCalc.setProperty(teCalc.PROP_TAU_SEARCH_MAX, "1");
|
||||
teCalc.setProperty(teCalc.PROP_AUTO_EMBED_METHOD, teCalc.AUTO_EMBED_METHOD_MAX_CORR_AIS_AND_TE);
|
||||
teCalc.setDebug(true);
|
||||
|
||||
// Run optimisation
|
||||
teCalc.initialise();
|
||||
teCalc.setObservations(source, target);
|
||||
int optimisedK = Integer.parseInt(teCalc.getProperty(TransferEntropyCalculatorKraskov.K_PROP_NAME));
|
||||
int optimisedL = Integer.parseInt(teCalc.getProperty(TransferEntropyCalculatorKraskov.L_PROP_NAME));
|
||||
|
||||
// Test that answer was correct
|
||||
assertEquals(correctK, optimisedK);
|
||||
assertEquals(correctL, optimisedL);
|
||||
}
|
||||
|
||||
public void testAutoEmbeddingTEWithValidity() throws Exception {
|
||||
System.out.println("Start AIS+TE autoembedding test.");
|
||||
|
||||
// Generate multivariate data (note that source time series has no memory)
|
||||
RandomGenerator rg = new RandomGenerator();
|
||||
double[] source = rg.generateNormalData(20000, 0, 1);
|
||||
double[] target = rg.generateNormalData(20000, 0, 1);
|
||||
boolean[] validity = new boolean[target.length];
|
||||
Random random = new Random();
|
||||
for (int t = 0; t < target.length; t++) {
|
||||
if (random.nextDouble() < 0.05) {
|
||||
validity[t] = false;
|
||||
} else {
|
||||
validity[t] = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=3; i < source.length; i++) {
|
||||
target[i] = 0.2*source[i-2] + 0.2*source[i-1] +
|
||||
0.2*target[i-2] + 0.2*target[i-1] + target[i];
|
||||
}
|
||||
|
||||
int correctK = 2;
|
||||
int correctL = 2;
|
||||
|
||||
// Instantiate calculator and set search bounds
|
||||
TransferEntropyCalculatorGaussian teCalc =
|
||||
new TransferEntropyCalculatorGaussian();
|
||||
teCalc.setProperty("k", "4");
|
||||
teCalc.setProperty(teCalc.PROP_K_SEARCH_MAX, "2");
|
||||
teCalc.setProperty(teCalc.PROP_TAU_SEARCH_MAX, "1");
|
||||
teCalc.setProperty(teCalc.PROP_AUTO_EMBED_METHOD, teCalc.AUTO_EMBED_METHOD_MAX_CORR_AIS_AND_TE);
|
||||
teCalc.setDebug(true);
|
||||
|
||||
// Run optimisation
|
||||
teCalc.initialise();
|
||||
teCalc.setObservations(source, target, validity, validity);
|
||||
int optimisedK = Integer.parseInt(teCalc.getProperty(TransferEntropyCalculatorKraskov.K_PROP_NAME));
|
||||
int optimisedL = Integer.parseInt(teCalc.getProperty(TransferEntropyCalculatorKraskov.L_PROP_NAME));
|
||||
|
||||
// Test that answer was correct
|
||||
assertEquals(correctK, optimisedK);
|
||||
assertEquals(correctL, optimisedL);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -646,8 +646,8 @@ public class TransferEntropyTester
|
|||
|
||||
// Generate multivariate data (note that source time series has no memory)
|
||||
RandomGenerator rg = new RandomGenerator();
|
||||
double[] source = rg.generateNormalData(5000, 0, 1);
|
||||
double[] target = rg.generateNormalData(5000, 0, 1);
|
||||
double[] source = rg.generateNormalData(10000, 0, 1);
|
||||
double[] target = rg.generateNormalData(10000, 0, 1);
|
||||
|
||||
for (int i=3; i < source.length; i++) {
|
||||
target[i] = 0.2*source[i-2] + 0.2*source[i-1] +
|
||||
|
@ -682,8 +682,8 @@ public class TransferEntropyTester
|
|||
|
||||
// Generate multivariate data (note that source time series has no memory)
|
||||
RandomGenerator rg = new RandomGenerator();
|
||||
double[] source = rg.generateNormalData(10000, 0, 1);
|
||||
double[] target = rg.generateNormalData(10000, 0, 1);
|
||||
double[] source = rg.generateNormalData(20000, 0, 1);
|
||||
double[] target = rg.generateNormalData(20000, 0, 1);
|
||||
boolean[] validity = new boolean[target.length];
|
||||
Random random = new Random();
|
||||
for (int t = 0; t < target.length; t++) {
|
||||
|
|
Loading…
Reference in New Issue