mirror of https://github.com/jlizier/jidt
Added interface for ConditionalTransferEntropy. Added abstract implementation ConditionalTransferEntropyCalculatorViaCondMutualInfo, and child classes for Kraskov and Gaussian implementations.
Added associated embedding method to MatrixUtils, and fixed a lot of header comments here. Minor fixes to comments and which methods are specified (e.g. setProperties) for TransferEntropy and Entropy calculators.
This commit is contained in:
parent
ac607078d5
commit
83f7de5472
|
|
@ -52,6 +52,8 @@ public interface ActiveInfoStorageCalculator {
|
|||
|
||||
/**
|
||||
* Allows the user to set properties for the underlying calculator implementation
|
||||
* New property values are not guaranteed to take effect until the next call
|
||||
* to an initialise method.
|
||||
*
|
||||
* @param propertyName
|
||||
* @param propertyValue
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ package infodynamics.measures.continuous;
|
|||
*/
|
||||
public interface ChannelCalculator extends ChannelCalculatorCommon {
|
||||
|
||||
public void initialise() throws Exception;
|
||||
|
||||
/**
|
||||
* <p>Sets the single set of observations to compute the PDFs from.
|
||||
* Cannot be called in conjunction with
|
||||
|
|
|
|||
|
|
@ -18,7 +18,17 @@ import infodynamics.utils.EmpiricalMeasurementDistribution;
|
|||
public abstract interface ChannelCalculatorCommon {
|
||||
|
||||
/**
|
||||
* Allows the user to set properties for the underlying calculator implementation
|
||||
* Initialise the calculator for re-use with new observations.
|
||||
* All parameters remain unchanged.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void initialise() throws Exception;
|
||||
|
||||
/**
|
||||
* Allows the user to set properties for the underlying calculator implementation.
|
||||
* New property values are not guaranteed to take effect until the next call
|
||||
* to an initialise method.
|
||||
*
|
||||
* @param propertyName
|
||||
* @param propertyValue
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ public interface ConditionalMutualInfoCalculatorMultiVariate {
|
|||
|
||||
/**
|
||||
* Allows the user to set properties for the underlying calculator implementation
|
||||
* New property values are not guaranteed to take effect until the next call
|
||||
* to an initialise method.
|
||||
*
|
||||
* @param propertyName
|
||||
* @param propertyValue
|
||||
|
|
|
|||
|
|
@ -120,6 +120,8 @@ public abstract class ConditionalMutualInfoMultiVariateCommon implements
|
|||
|
||||
/**
|
||||
* Sets common properties for the calculator.
|
||||
* New property values are not guaranteed to take effect until the next call
|
||||
* to an initialise method.
|
||||
* Valid properties include:
|
||||
* <ul>
|
||||
* <li>{@link #PROP_NORMALISE} - whether to normalise the individual
|
||||
|
|
|
|||
|
|
@ -0,0 +1,350 @@
|
|||
package infodynamics.measures.continuous;
|
||||
|
||||
/**
|
||||
* <p>This specifies the interface for implementations of
|
||||
* the conditional transfer entropy
|
||||
* and local conditional transfer entropy
|
||||
* (see Lizier et al. PRE, 2008, and Lizier et al., Chaos 2010).
|
||||
* </p>
|
||||
*
|
||||
* <p>Specifically, this specifies the interface for computing
|
||||
* the transfer entropy for <i>continuous</i>-valued variables.</p>
|
||||
*
|
||||
* @see "Schreiber, Physical Review Letters 85 (2) pp.461-464 (2000);
|
||||
* <a href='http://dx.doi.org/10.1103/PhysRevLett.85.461'>download</a>
|
||||
* (for definition of transfer entropy)"
|
||||
* @see "Lizier, Prokopenko and Zomaya, Physical Review E 77, 026110 (2008);
|
||||
* <a href='http://dx.doi.org/10.1103/PhysRevE.77.026110'>download</a>
|
||||
* (for the extension to <i>conditional</i> transfer entropy
|
||||
* or <i>complete</i> where all other causal sources are conditioned on,
|
||||
* and <i>local</i> transfer entropy)"
|
||||
* @see "Lizier, Prokopenko and Zomaya, Chaos 20, 3, 037109 (2010);
|
||||
* <a href='http://dx.doi.org/10.1063/1.3486801'>download</a>
|
||||
* (for further clarification on <i>conditional</i> transfer entropy
|
||||
* or <i>complete</i> where all other causal sources are conditioned on)"
|
||||
*
|
||||
* @author Joseph Lizier, <a href="joseph.lizier at gmail.com">email</a>,
|
||||
* <a href="http://lizier.me/joseph/">www</a>
|
||||
*
|
||||
*/
|
||||
public interface ConditionalTransferEntropyCalculator extends ChannelCalculatorCommon {
|
||||
|
||||
/**
|
||||
* Property name to specify the history length k
|
||||
*/
|
||||
public static final String K_PROP_NAME = "k_HISTORY";
|
||||
/**
|
||||
* Embedding delay for the destination past history vector
|
||||
*/
|
||||
public static final String K_TAU_PROP_NAME = "k_TAU";
|
||||
/**
|
||||
* Embedding length for the source past history vector
|
||||
*/
|
||||
public static final String L_PROP_NAME = "l_HISTORY";
|
||||
/**
|
||||
* Embedding delay for the source past history vector
|
||||
*/
|
||||
public static final String L_TAU_PROP_NAME = "l_TAU";
|
||||
/**
|
||||
* Source-destination delay
|
||||
*/
|
||||
public static final String DELAY_PROP_NAME = "DELAY";
|
||||
/**
|
||||
* Property name for embedding lengths of conditional variables
|
||||
*/
|
||||
public static final String COND_EMBED_LENGTHS_PROP_NAME = "COND_EMBED_LENGTHS";
|
||||
/**
|
||||
* Property name for embedding delays of conditional variables
|
||||
*/
|
||||
public static final String COND_EMBED_DELAYS_PROP_NAME = "COND_TAUS";
|
||||
/**
|
||||
* Property name for conditional-destination delays of conditional variables
|
||||
*/
|
||||
public static final String COND_DELAYS_PROP_NAME = "COND_DELAYS";
|
||||
|
||||
/**
|
||||
* Initialise the calculator for re-use with new observations.
|
||||
* A new history length k can be supplied here; all other parameters
|
||||
* remain unchanged.
|
||||
*
|
||||
* @param k history length to be considered.
|
||||
* @throws Exception
|
||||
*/
|
||||
public void initialise(int k) throws Exception;
|
||||
|
||||
/**
|
||||
* Initialise the calculator for a single conditional
|
||||
* variable, with the given destination,
|
||||
* source and conditional embedding length, setting all
|
||||
* embedding delays to 1, and the source-dest and
|
||||
* conditional-dest delays to 1.
|
||||
*
|
||||
* @param k Length of destination past history to consider
|
||||
* @param l length of source past history to consider
|
||||
* @param condEmbedDim embedding length for one conditional variable.
|
||||
* Can be 0 if there are no conditional variables.
|
||||
* @throws Exception
|
||||
*/
|
||||
public void initialise(int k, int l, int condEmbedDim) throws Exception;
|
||||
|
||||
/**
|
||||
* Initialise the calculator with all required parameters supplied,
|
||||
* for a single conditional variable.
|
||||
*
|
||||
* @param k Length of destination past history to consider
|
||||
* @param k_tau embedding delay for the destination variable
|
||||
* @param l length of source past history to consider
|
||||
* @param l_tau embedding delay for the source variable
|
||||
* @param delay time lag between last element of source and destination next value
|
||||
* @param condEmbedDim embedding lengths for one conditional variable.
|
||||
* Can be 0 if there are no conditional variables.
|
||||
* @param cond_tau embedding delay for the conditional variable.
|
||||
* Ignored if condEmbedDim == 0.
|
||||
* @param condDelay time lags between last element of the conditional variable
|
||||
* and destination next value.
|
||||
* Ignored if condEmbedDim == 0.
|
||||
* @throws Exception for inconsistent arguments, e.g. if array lengths differ between
|
||||
* condEmbedDims, cond_taus and condDelays.
|
||||
*/
|
||||
public void initialise(int k, int k_tau, int l, int l_tau, int delay,
|
||||
int condEmbedDim, int cond_tau, int condDelay) throws Exception;
|
||||
/**
|
||||
* Initialise the calculator with all required parameters supplied.
|
||||
*
|
||||
* @param k Length of destination past history to consider
|
||||
* @param k_tau embedding delay for the destination variable
|
||||
* @param l length of source past history to consider
|
||||
* @param l_tau embedding delay for the source variable
|
||||
* @param delay time lag between last element of source and destination next value
|
||||
* @param condEmbedDims array of embedding lengths for each conditional variable.
|
||||
* Can be an empty array or null if there are no conditional variables.
|
||||
* @param cond_taus array of embedding delays for the conditional variables.
|
||||
* Must be same length as condEmbedDims array.
|
||||
* @param condDelays array of time lags between last element of each conditional variable
|
||||
* and destination next value.
|
||||
* Must be same length as condEmbedDims array.
|
||||
* @throws Exception for inconsistent arguments, e.g. if array lengths differ between
|
||||
* condEmbedDims, cond_taus and condDelays.
|
||||
*/
|
||||
public void initialise(int k, int k_tau, int l, int l_tau, int delay,
|
||||
int[] condEmbedDims, int[] cond_taus, int[] condDelays) throws Exception;
|
||||
|
||||
/**
|
||||
* <p>Set the given property to the given value.
|
||||
* New property values are not guaranteed to take effect until the next call
|
||||
* to an initialise method.
|
||||
* These can include:
|
||||
* <ul>
|
||||
* <li>{@link #K_PROP_NAME}</li>
|
||||
* <li>{@link #K_TAU_PROP_NAME}</li>
|
||||
* <li>{@link #L_PROP_NAME}</li>
|
||||
* <li>{@link #L_TAU_PROP_NAME}</li>
|
||||
* <li>{@link #DELAY_PROP_NAME}</li>
|
||||
* <li>{@link #COND_EMBED_LENGTHS_PROP_NAME} -- as a comma separated integer list</li>
|
||||
* <li>{@link #COND_EMBED_DELAYS_PROP_NAME} -- as a comma separated integer list</li>
|
||||
* <li>{@link #COND_DELAYS_PROP_NAME} -- as a comma separated integer list</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
|
||||
*/
|
||||
public void setProperty(String propertyName, String propertyValue) throws Exception;
|
||||
|
||||
/**
|
||||
* <p>Sets the single set of observations to compute the PDFs from.
|
||||
* Cannot be called in conjunction with
|
||||
* {@link #startAddObservations()}/{@link #addObservations(double[], double[], double[][])} /
|
||||
* {@link #finaliseAddObservations()}.</p>
|
||||
*
|
||||
* @param source observations for the source variable
|
||||
* @param destination observations for the destination variable
|
||||
* @param conditionals 2D time series array for the conditional variables
|
||||
* (first index is time, second index is variable number)
|
||||
* @throws Exception
|
||||
*/
|
||||
public void setObservations(double[] source, double[] destination, double[][] conditionals) throws Exception;
|
||||
|
||||
/**
|
||||
* <p>Sets the single set of observations to compute the PDFs from.
|
||||
* Cannot be called in conjunction with
|
||||
* {@link #startAddObservations()}/{@link #addObservations(double[], double[], double[][])} /
|
||||
* {@link #finaliseAddObservations()}.</p>
|
||||
*
|
||||
* @param source observations for the source variable
|
||||
* @param destination observations for the destination variable
|
||||
* @param conditionals 1D time series array for the conditional variables
|
||||
* -- valid only if the calculator was initialised for a single
|
||||
* conditional variable.
|
||||
* @throws Exception for example if the calculator was not initialised for
|
||||
* a single conditional variable
|
||||
*/
|
||||
public void setObservations(double[] source, double[] destination, double[] conditionals) throws Exception;
|
||||
|
||||
/**
|
||||
* <p>Adds a new set of observations to update the PDFs with - is
|
||||
* intended to be called multiple times.
|
||||
* Must be called after {@link #startAddObservations()}; call
|
||||
* {@link #finaliseAddObservations()} once all observations have
|
||||
* been supplied.</p>
|
||||
*
|
||||
* <p><b>Important:</b> this does not append these observations to the previously
|
||||
* supplied observations, but treats them independently - i.e. measurements
|
||||
* such as the transfer entropy will not join them up to examine k
|
||||
* consecutive values in time.</p>
|
||||
*
|
||||
* <p>Note that the arrays source, destination and conditionals must not be over-written by the user
|
||||
* until after finaliseAddObservations() has been called
|
||||
* (they are not copied by this method necessarily, but the method
|
||||
* may simply hold a pointer to them).</p>
|
||||
*
|
||||
* @param source observations for the source variable
|
||||
* @param destination observations for the destination variable
|
||||
* @param conditionals 2D time series array for the conditional variables
|
||||
* (first index is time, second index is variable number)
|
||||
* @throws Exception
|
||||
*/
|
||||
public void addObservations(double[] source, double[] destination, double[][] conditionals) throws Exception;
|
||||
|
||||
/**
|
||||
* <p>Adds a new set of observations to update the PDFs with - is
|
||||
* intended to be called multiple times.
|
||||
* Must be called after {@link #startAddObservations()}; call
|
||||
* {@link #finaliseAddObservations()} once all observations have
|
||||
* been supplied.</p>
|
||||
*
|
||||
* <p><b>Important:</b> this does not append these observations to the previously
|
||||
* supplied observations, but treats them independently - i.e. measurements
|
||||
* such as the transfer entropy will not join them up to examine k
|
||||
* consecutive values in time.</p>
|
||||
*
|
||||
* <p>Note that the arrays source, destination and conditionals must not be over-written by the user
|
||||
* until after finaliseAddObservations() has been called
|
||||
* (they are not copied by this method necessarily, but the method
|
||||
* may simply hold a pointer to them).</p>
|
||||
*
|
||||
* @param source observations for the source variable
|
||||
* @param destination observations for the destination variable
|
||||
* @param conditionals 1D time series array for the conditional variables
|
||||
* -- valid only if the calculator was initialised for a single
|
||||
* conditional variable.
|
||||
* @throws Exception for example if the calculator was not initialised for
|
||||
* a single conditional variable
|
||||
*/
|
||||
public void addObservations(double[] source, double[] destination, double[] conditionals) throws Exception;
|
||||
|
||||
/**
|
||||
* <p>Adds a new set of observations to update the PDFs with - is
|
||||
* intended to be called multiple times.
|
||||
* Must be called after {@link #startAddObservations()}; call
|
||||
* {@link #finaliseAddObservations()} once all observations have
|
||||
* been supplied.</p>
|
||||
*
|
||||
* <p><b>Important:</b> this does not append these observations to the previously
|
||||
* supplied observations, but treats them independently - i.e. measurements
|
||||
* such as the transfer entropy will not join them up to examine k
|
||||
* consecutive values in time.</p>
|
||||
*
|
||||
* <p>Note that the arrays source, destination and conditionals must not be over-written by the user
|
||||
* until after finaliseAddObservations() has been called
|
||||
* (they are not copied by this method necessarily, but the method
|
||||
* may simply hold a pointer to them).</p>
|
||||
*
|
||||
* @param source observations for the source variable
|
||||
* @param destination observations for the destination variable
|
||||
* @param conditionals 2D time series array for the conditional variables
|
||||
* (first index is time, second index is variable number)
|
||||
* @param startTime first time index to take observations on
|
||||
* @param numTimeSteps number of time steps to use
|
||||
* @throws Exception
|
||||
*/
|
||||
public void addObservations(double[] source, double[] destination,
|
||||
double[][] conditionals,
|
||||
int startTime, int numTimeSteps) throws Exception ;
|
||||
|
||||
/**
|
||||
* <p>Adds a new set of observations to update the PDFs with - is
|
||||
* intended to be called multiple times.
|
||||
* Must be called after {@link #startAddObservations()}; call
|
||||
* {@link #finaliseAddObservations()} once all observations have
|
||||
* been supplied.</p>
|
||||
*
|
||||
* <p><b>Important:</b> this does not append these observations to the previously
|
||||
* supplied observations, but treats them independently - i.e. measurements
|
||||
* such as the transfer entropy will not join them up to examine k
|
||||
* consecutive values in time.</p>
|
||||
*
|
||||
* <p>Note that the arrays source, destination and conditionals must not be over-written by the user
|
||||
* until after finaliseAddObservations() has been called
|
||||
* (they are not copied by this method necessarily, but the method
|
||||
* may simply hold a pointer to them).</p>
|
||||
*
|
||||
* @param source observations for the source variable
|
||||
* @param destination observations for the destination variable
|
||||
* @param conditionals 1D time series array for the conditional variables
|
||||
* -- valid only if the calculator was initialised for a single
|
||||
* conditional variable.
|
||||
* @param startTime first time index to take observations on
|
||||
* @param numTimeSteps number of time steps to use
|
||||
* @throws Exception for example if the calculator was not initialised for
|
||||
* a single conditional variable
|
||||
*/
|
||||
public void addObservations(double[] source, double[] destination,
|
||||
double[] conditionals,
|
||||
int startTime, int numTimeSteps) throws Exception ;
|
||||
|
||||
/**
|
||||
* <p>Sets the single set of observations to compute the PDFs from.
|
||||
* Cannot be called in conjunction with
|
||||
* {@link #startAddObservations()}/{@link #addObservations(double[], double[])} /
|
||||
* {@link #finaliseAddObservations()}.</p>
|
||||
*
|
||||
* @param source observations for the source variable
|
||||
* @param destination observations for the destination variable
|
||||
* @param conditionals 2D time series array for the conditional variables
|
||||
* (first index is time, second index is variable number)
|
||||
* @param sourceValid time series (with time indices the same as source)
|
||||
* indicating whether the source at that point is valid.
|
||||
* @param destValid time series (with time indices the same as destination)
|
||||
* indicating whether the destination at that point is valid.
|
||||
* @param conditionalsValid 2D time series (with time indices the same as conditionals)
|
||||
* indicating whether the conditional variables at that point are valid.
|
||||
* @throws Exception
|
||||
*/
|
||||
public void setObservations(double[] source, double[] destination,
|
||||
double[][] conditionals,
|
||||
boolean[] sourceValid, boolean[] destValid, boolean[][] conditionalsValid) throws Exception;
|
||||
|
||||
/**
|
||||
* Compute local conditional transfer entropy values for the
|
||||
* observations in the given parameters,
|
||||
* using the PDFs computed from the previously supplied method calls.
|
||||
*
|
||||
* @param newSourceObservations new observations for the source variable
|
||||
* @param newDestObservations new observations for the destination variable
|
||||
* @param newCondObservations new observations for the conditional variables
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public double[] computeLocalUsingPreviousObservations(
|
||||
double[] newSourceObservations, double[] newDestObservations,
|
||||
double[][] newCondObservations) throws Exception;
|
||||
|
||||
/**
|
||||
* Compute local conditional transfer entropy values for the
|
||||
* observations in the given parameters,
|
||||
* using the PDFs computed from the previously supplied method calls.
|
||||
*
|
||||
* @param newSourceObservations new observations for the source variable
|
||||
* @param newDestObservations new observations for the destination variable
|
||||
* @param newCondObservations 1D time series array for the conditional variables
|
||||
* -- valid only if the calculator was initialised for a single
|
||||
* conditional variable.
|
||||
* @return
|
||||
* @throws Exception for example if the calculator was not initialised for
|
||||
* a single conditional variable
|
||||
*/
|
||||
public double[] computeLocalUsingPreviousObservations(
|
||||
double[] newSourceObservations, double[] newDestObservations,
|
||||
double[] newCondObservations) throws Exception;
|
||||
}
|
||||
|
|
@ -0,0 +1,803 @@
|
|||
package infodynamics.measures.continuous;
|
||||
|
||||
import infodynamics.utils.EmpiricalMeasurementDistribution;
|
||||
import infodynamics.utils.MatrixUtils;
|
||||
import infodynamics.utils.ParsedProperties;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* <p>An abstract Conditional Transfer entropy calculator which is implemented using a
|
||||
* Conditional Mutual Information calculator.
|
||||
* The Conditional Mutual Information calculator must be supplied at construction time.
|
||||
* </p>
|
||||
*
|
||||
* <p>There are no abstract methods of this class, and conceivably it could be constructed
|
||||
* with a {@link ConditionalMutualInfoCalculatorMultiVariate} class supplied,
|
||||
* however there are typically extra considerations for each estimator type.
|
||||
* As such, the children of this abstract class provide concrete implementations using various
|
||||
* estimator types; see e.g. {@link infodynamics.continuous.gaussian.ConditionalTransferEntropyCalculatorGaussian}.
|
||||
* </p>
|
||||
*
|
||||
* @see "Schreiber, Physical Review Letters 85 (2) pp.461-464 (2000);
|
||||
* <a href='http://dx.doi.org/10.1103/PhysRevLett.85.461'>download</a>
|
||||
* (for definition of transfer entropy)"
|
||||
* @see "Lizier, Prokopenko and Zomaya, Physical Review E 77, 026110 (2008);
|
||||
* <a href='http://dx.doi.org/10.1103/PhysRevE.77.026110'>download</a>
|
||||
* (for the extension to <i>conditional</i> transfer entropy
|
||||
* or <i>complete</i> where all other causal sources are conditioned on,
|
||||
* and <i>local</i> transfer entropy)"
|
||||
* @see "Lizier, Prokopenko and Zomaya, Chaos 20, 3, 037109 (2010);
|
||||
* <a href='http://dx.doi.org/10.1063/1.3486801'>download</a>
|
||||
* (for further clarification on <i>conditional</i> transfer entropy
|
||||
* or <i>complete</i> where all other causal sources are conditioned on)"
|
||||
*
|
||||
* @author Joseph Lizier, <a href="joseph.lizier at gmail.com">email</a>,
|
||||
* <a href="http://lizier.me/joseph/">www</a>
|
||||
*/
|
||||
public abstract class ConditionalTransferEntropyCalculatorViaCondMutualInfo implements
|
||||
ConditionalTransferEntropyCalculator {
|
||||
|
||||
/**
|
||||
* Underlying conditional mutual information calculator
|
||||
*/
|
||||
protected ConditionalMutualInfoCalculatorMultiVariate condMiCalc;
|
||||
/**
|
||||
* Length of past destination history to consider (embedding length)
|
||||
*/
|
||||
protected int k = 1;
|
||||
/**
|
||||
* Embedding delay to use between elements of the destination embeding vector.
|
||||
* We're hard-coding a delay of 1 between the history vector and the next
|
||||
* observation however.
|
||||
*/
|
||||
protected int k_tau = 1;
|
||||
/**
|
||||
* Length of past source history to consider (embedding length)
|
||||
*/
|
||||
protected int l = 1;
|
||||
/**
|
||||
* Embedding delay to use between elements of the source embeding vector.
|
||||
*/
|
||||
protected int l_tau = 1;
|
||||
/**
|
||||
* Source-destination next observation delay
|
||||
*/
|
||||
protected int delay = 1;
|
||||
/**
|
||||
* Array of embedding lengths for each conditional variable.
|
||||
* Can be an empty array or null if there are no conditional variables.
|
||||
*/
|
||||
protected int[] condEmbedDims = null;
|
||||
/**
|
||||
* Array of embedding delays for the conditional variables.
|
||||
* Must be same length as condEmbedDims array.
|
||||
*/
|
||||
protected int[] cond_taus = null;
|
||||
/**
|
||||
* Array of time lags between last element of each conditional variable
|
||||
* and destination next value.
|
||||
*/
|
||||
protected int[] condDelays = null;
|
||||
|
||||
/**
|
||||
* Time index of the last point in the destination embedding of the first
|
||||
* (destination past, source past, destination next) tuple than can be
|
||||
* taken from any set of time-series observations.
|
||||
*/
|
||||
protected int startTimeForFirstDestEmbedding;
|
||||
|
||||
/**
|
||||
* The total dimensionality of our embedded conditional values
|
||||
* (sum of condEmbedDims)
|
||||
*/
|
||||
protected int dimOfConditionals = 0;
|
||||
|
||||
protected boolean debug = false;
|
||||
|
||||
/**
|
||||
* Construct a conditional transfer entropy calculator using an instance of
|
||||
* condMiCalculatorClassName as the underlying conditional mutual information calculator.
|
||||
*
|
||||
* @param condMiCalculatorClassName name of the class which must implement
|
||||
* {@link ConditionalMutualInfoCalculatorMultiVariate}
|
||||
* @throws InstantiationException if the given class cannot be instantiated
|
||||
* @throws IllegalAccessException if illegal access occurs while trying to create an instance
|
||||
* of the class
|
||||
* @throws ClassNotFoundException if the given class is not found
|
||||
*/
|
||||
public ConditionalTransferEntropyCalculatorViaCondMutualInfo(String condMiCalculatorClassName)
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<ConditionalMutualInfoCalculatorMultiVariate> condMiClass =
|
||||
(Class<ConditionalMutualInfoCalculatorMultiVariate>) Class.forName(condMiCalculatorClassName);
|
||||
ConditionalMutualInfoCalculatorMultiVariate condMiCalc = condMiClass.newInstance();
|
||||
construct(condMiCalc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a conditional transfer entropy calculator using an instance of
|
||||
* condMiCalcClass as the underlying conditional mutual information calculator.
|
||||
*
|
||||
* @param condMiCalcClass the class which must implement
|
||||
* {@link ConditionalMutualInfoCalculatorMultiVariate}
|
||||
* @throws InstantiationException if the given class cannot be instantiated
|
||||
* @throws IllegalAccessException if illegal access occurs while trying to create an instance
|
||||
* of the class
|
||||
* @throws ClassNotFoundException if the given class is not found
|
||||
*/
|
||||
public ConditionalTransferEntropyCalculatorViaCondMutualInfo(Class<ConditionalMutualInfoCalculatorMultiVariate> condMiCalcClass)
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
|
||||
ConditionalMutualInfoCalculatorMultiVariate condMiCalc = condMiCalcClass.newInstance();
|
||||
construct(condMiCalc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct this calculator by passing in a constructed but not initialised
|
||||
* underlying Conditional Mutual information calculator.
|
||||
*
|
||||
* @param condMiCalc An instantiated conditional mutual information calculator.
|
||||
* @throws Exception if the supplied calculator has not yet been instantiated.
|
||||
*/
|
||||
public ConditionalTransferEntropyCalculatorViaCondMutualInfo(ConditionalMutualInfoCalculatorMultiVariate condMiCalc) throws Exception {
|
||||
if (condMiCalc == null) {
|
||||
throw new Exception("Conditional MI calculator used to construct ConditionalTransferEntropyCalculatorViaCondMutualInfo " +
|
||||
" must have already been instantiated.");
|
||||
}
|
||||
construct(condMiCalc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to set the conditional mutual information calculator.
|
||||
* Can be overridden if anything else needs to be done with it by the child classes.
|
||||
*
|
||||
* @param condMiCalc
|
||||
*/
|
||||
protected void construct(ConditionalMutualInfoCalculatorMultiVariate condMiCalc) {
|
||||
this.condMiCalc = condMiCalc;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ChannelCalculatorCommon#initialise()
|
||||
*/
|
||||
public void initialise() throws Exception {
|
||||
initialise(k, k_tau, l, l_tau, delay, condEmbedDims, cond_taus, condDelays);
|
||||
}
|
||||
|
||||
public void initialise(int k) throws Exception {
|
||||
initialise(k, k_tau, l, l_tau, delay, condEmbedDims, cond_taus, condDelays);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ConditionalTransferEntropyCalculator#initialise(int, int, int)
|
||||
*/
|
||||
public void initialise(int k, int l, int condEmbedDim) throws Exception {
|
||||
if (condEmbedDim == 0) {
|
||||
// No conditional variables:
|
||||
initialise(k, 1, l, 1, 1, null, null, null);
|
||||
} else {
|
||||
// We have a conditional variable:
|
||||
int[] condEmbedDimsArray = new int[1];
|
||||
condEmbedDimsArray[0] = condEmbedDim;
|
||||
int[] cond_taus = new int[1];
|
||||
cond_taus[0] = 1;
|
||||
int[] cond_delays = new int[1];
|
||||
cond_delays[0] = 1;
|
||||
initialise(k, 1, l, 1, 1, condEmbedDimsArray, cond_taus, cond_delays);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ConditionalTransferEntropyCalculator#initialise(int, int, int, int, int, int, int, int)
|
||||
*/
|
||||
public void initialise(int k, int k_tau, int l, int l_tau, int delay,
|
||||
int condEmbedDim, int cond_tau, int condDelay) throws Exception {
|
||||
if (condEmbedDim == 0) {
|
||||
// No conditional variables:
|
||||
initialise(k, k_tau, l, l_tau, delay, null, null, null);
|
||||
} else {
|
||||
// We have a conditional variable:
|
||||
int[] condEmbedDimsArray = new int[1];
|
||||
condEmbedDimsArray[0] = condEmbedDim;
|
||||
int[] cond_taus = new int[1];
|
||||
cond_taus[0] = cond_tau;
|
||||
int[] cond_delays = new int[1];
|
||||
cond_delays[0] = condDelay;
|
||||
initialise(k, k_tau, l, l_tau, delay, condEmbedDimsArray, cond_taus, cond_delays);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ConditionalTransferEntropyCalculator#initialise(int, int, int, int, int, int[], int[], int[])
|
||||
*/
|
||||
public void initialise(int k, int k_tau, int l, int l_tau, int delay,
|
||||
int[] condEmbedDims, int[] cond_taus, int[] condDelays)
|
||||
throws Exception {
|
||||
|
||||
// First, check consistency:
|
||||
if (delay < 0) {
|
||||
throw new Exception("Cannot compute TE with source-destination delay < 0");
|
||||
}
|
||||
if (condEmbedDims == null) {
|
||||
// Allow this if all conditional parameter arrays null or 0 length
|
||||
condEmbedDims = new int[0];
|
||||
}
|
||||
if (cond_taus == null) {
|
||||
// Allow this if all conditional parameter arrays null or 0 length
|
||||
cond_taus = new int[0];
|
||||
}
|
||||
if (condDelays == null) {
|
||||
// Allow this if all conditional parameter arrays null or 0 length
|
||||
condDelays = new int[0];
|
||||
}
|
||||
if ((condEmbedDims.length != cond_taus.length) ||
|
||||
(condEmbedDims.length != condDelays.length)) {
|
||||
throw new Exception("condEmbedDims, cond_taus and condDelays must have" +
|
||||
" same length in argument to ConditionalTransferEntropyCalculatorViaCondMutualInfo.initialise()");
|
||||
}
|
||||
for (int i = 0; i < condDelays.length; i++) {
|
||||
if (condDelays[i] < 0) {
|
||||
throw new Exception("Cannot compute TE with conditional-destination delay < 0");
|
||||
}
|
||||
}
|
||||
|
||||
// Next, store the parameters.
|
||||
this.k = k;
|
||||
this.k_tau = k_tau;
|
||||
this.l = l;
|
||||
this.l_tau = l_tau;
|
||||
this.delay = delay;
|
||||
this.condEmbedDims = condEmbedDims;
|
||||
this.cond_taus = cond_taus;
|
||||
this.condDelays = condDelays;
|
||||
|
||||
// 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, or the case where
|
||||
// the conditional embeding 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;
|
||||
int startTimeBasedOnCondPast = 0;
|
||||
dimOfConditionals = 0;
|
||||
for (int i = 0; i < condDelays.length; i++) {
|
||||
// Check what the start time would be based on this conditional variable
|
||||
int startTimeBasedOnThisConditional =
|
||||
(condEmbedDims[i]-1)*cond_taus[i] + condDelays[i] - 1;
|
||||
if (startTimeBasedOnThisConditional > startTimeBasedOnCondPast) {
|
||||
startTimeBasedOnCondPast = startTimeBasedOnThisConditional;
|
||||
}
|
||||
// And while we're looping compute the total dimension of conditionals
|
||||
dimOfConditionals += condEmbedDims[i];
|
||||
}
|
||||
startTimeForFirstDestEmbedding = Math.max(startTimeBasedOnDestPast,
|
||||
Math.max(startTimeBasedOnSourcePast, startTimeBasedOnCondPast));
|
||||
|
||||
condMiCalc.initialise(l, 1, k + dimOfConditionals);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Set the given property to the given value.
|
||||
* New property values are not guaranteed to take effect until the next call
|
||||
* to an initialise method.
|
||||
* These can include the following properties from {@link ConditionalTransferEntropyCalculator}:
|
||||
* <ul>
|
||||
* <li>{@link #K_PROP_NAME}</li>
|
||||
* <li>{@link #K_TAU_PROP_NAME}</li>
|
||||
* <li>{@link #L_PROP_NAME}</li>
|
||||
* <li>{@link #L_TAU_PROP_NAME}</li>
|
||||
* <li>{@link #DELAY_PROP_NAME}</li>
|
||||
* <li>{@link #COND_EMBED_LENGTHS_PROP_NAME} - supplied as a comma separated integer list</li>
|
||||
* <li>{@link #COND_EMBED_DELAYS_PROP_NAME} - supplied as a comma separated integer list</li>
|
||||
* <li>{@link #COND_DELAYS_PROP_NAME} - supplied as a comma separated integer list</li>
|
||||
* </ul>
|
||||
* Note that you can pass in any of the last three properties as different length
|
||||
* arrays to the current values of the others; this will not be checked here (to allow
|
||||
* them to be changed here sequentially), but will be checked at the next initialisation
|
||||
* of the object.
|
||||
* </p>
|
||||
*
|
||||
* <p>Otherwise, it is assumed the property
|
||||
* is for the underlying {@link ConditionalMutualInfoCalculatorMultiVariate#setProperty(String, String)} implementation.
|
||||
* </p>
|
||||
*
|
||||
* @param propertyName name of the property
|
||||
* @param propertyValue value of the property.
|
||||
* @throws Exception if there is a problem with the supplied value
|
||||
*/
|
||||
public void setProperty(String propertyName, String propertyValue) throws Exception {
|
||||
boolean propertySet = true;
|
||||
if (propertyName.equalsIgnoreCase(K_PROP_NAME)) {
|
||||
k = Integer.parseInt(propertyValue);
|
||||
} else if (propertyName.equalsIgnoreCase(K_TAU_PROP_NAME)) {
|
||||
k_tau = Integer.parseInt(propertyValue);
|
||||
} else if (propertyName.equalsIgnoreCase(L_PROP_NAME)) {
|
||||
l = Integer.parseInt(propertyValue);
|
||||
} else if (propertyName.equalsIgnoreCase(L_TAU_PROP_NAME)) {
|
||||
l_tau = Integer.parseInt(propertyValue);
|
||||
} else if (propertyName.equalsIgnoreCase(DELAY_PROP_NAME)) {
|
||||
delay = Integer.parseInt(propertyValue);
|
||||
} else if (propertyName.equalsIgnoreCase(COND_EMBED_LENGTHS_PROP_NAME)) {
|
||||
condEmbedDims = ParsedProperties.parseStringArrayOfInts(propertyValue);
|
||||
} else if (propertyName.equalsIgnoreCase(COND_EMBED_DELAYS_PROP_NAME)) {
|
||||
cond_taus = ParsedProperties.parseStringArrayOfInts(propertyValue);
|
||||
} else if (propertyName.equalsIgnoreCase(COND_DELAYS_PROP_NAME)) {
|
||||
condDelays = ParsedProperties.parseStringArrayOfInts(propertyValue);
|
||||
} else {
|
||||
// No property was set on this class, assume it is for the underlying
|
||||
// conditional MI calculator
|
||||
condMiCalc.setProperty(propertyName, propertyValue);
|
||||
propertySet = false;
|
||||
}
|
||||
if (debug && propertySet) {
|
||||
System.out.println(this.getClass().getSimpleName() + ": Set property " + propertyName +
|
||||
" to " + propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ConditionalTransferEntropyCalculator#setObservations(double[], double[], double[][])
|
||||
*/
|
||||
public void setObservations(double[] source, double[] destination,
|
||||
double[][] conditionals) throws Exception {
|
||||
startAddObservations();
|
||||
addObservations(source, destination, conditionals);
|
||||
finaliseAddObservations();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ConditionalTransferEntropyCalculator#setObservations(double[], double[], double[])
|
||||
*/
|
||||
public void setObservations(double[] source, double[] destination,
|
||||
double[] conditionals) throws Exception {
|
||||
if (condEmbedDims.length != 1) {
|
||||
throw new Exception("Cannot call setObservations(double[], double[], double[]) when the " +
|
||||
"conditional TE calculator was not initialised for one conditional variable");
|
||||
}
|
||||
startAddObservations();
|
||||
addObservations(source, destination, conditionals);
|
||||
finaliseAddObservations();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ConditionalTransferEntropyCalculator#startAddObservations()
|
||||
*/
|
||||
public void startAddObservations() {
|
||||
condMiCalc.startAddObservations();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ConditionalTransferEntropyCalculator#addObservations(double[], double[], double[][])
|
||||
*/
|
||||
public void addObservations(double[] source, double[] destination,
|
||||
double[][] conditionals) 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 (conditionals == null) {
|
||||
if (condEmbedDims.length > 0) {
|
||||
throw new Exception(String.format("No conditionals supplied (expected %d-dimensional conditionals", condEmbedDims.length));
|
||||
} else {
|
||||
// This is allowed; make a dummy set of conditionals
|
||||
conditionals = new double[destination.length][0];
|
||||
}
|
||||
}
|
||||
if (conditionals.length != destination.length) {
|
||||
throw new Exception(String.format("Conditionals and destination lengths (%d and %d) must match!",
|
||||
conditionals.length, destination.length));
|
||||
}
|
||||
// Postcondition -- all time series have same length
|
||||
if (source.length < startTimeForFirstDestEmbedding + 2) {
|
||||
// There are no observations to add here, the time series is too short
|
||||
// Don't throw an exception, do nothing since more observations
|
||||
// can be added later.
|
||||
return;
|
||||
}
|
||||
if (conditionals[0].length != condEmbedDims.length) {
|
||||
throw new Exception(String.format("Number of conditional variables %d does not " +
|
||||
"match the initialised number %d", conditionals[0].length, condEmbedDims.length));
|
||||
}
|
||||
// All parameters are as expected
|
||||
double[][][] embeddedVectorsForCondMI =
|
||||
embedSourceDestAndConditionalsForCondMI(source, destination, conditionals);
|
||||
|
||||
condMiCalc.addObservations(embeddedVectorsForCondMI[0],
|
||||
embeddedVectorsForCondMI[1], embeddedVectorsForCondMI[2]);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ConditionalTransferEntropyCalculator#addObservations(double[], double[], double[])
|
||||
*/
|
||||
public void addObservations(double[] source, double[] destination,
|
||||
double[] conditionals) throws Exception {
|
||||
if (condEmbedDims.length != 1) {
|
||||
throw new Exception("Cannot call addObservations(double[], double[], double[]) when the " +
|
||||
"conditional TE calculator was not initialised for one conditional variable");
|
||||
}
|
||||
double[][] conditionalsIn2D = null;
|
||||
if (conditionals != null) {
|
||||
// This isn't incredibly efficient, but is easy to code and doesn't cost more
|
||||
// than an increase in the linear time multiplier.
|
||||
conditionalsIn2D = new double[conditionals.length][1];
|
||||
MatrixUtils.copyIntoColumn(conditionalsIn2D, 0, conditionals);
|
||||
}
|
||||
addObservations(source, destination, conditionalsIn2D);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to take (pre-screened) vectors for a source, destination
|
||||
* and conditional variables, and embed them using the given embedding
|
||||
* parameters, as well as combining the destination past and conditionals,
|
||||
* making all ready for a conditional MI calculation.
|
||||
*
|
||||
* @param source source time series observations
|
||||
* @param destination destination time series observations
|
||||
* @param conditionals 2D array of conditional time series observations.
|
||||
* @return double[][][] returnValue; where returnValue[0] is the embedded
|
||||
* source vectors, returnValue[1] is the destination next values,
|
||||
* and returnValue[2] is the joined embedded destination past
|
||||
* and conditionals.
|
||||
* @throws Exception
|
||||
*/
|
||||
protected double[][][] embedSourceDestAndConditionalsForCondMI(double[] source, double[] destination,
|
||||
double[][] conditionals) throws Exception {
|
||||
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);
|
||||
// Now combine the destination past vectors with the conditionals:
|
||||
double[][] currentCombinedConditionalVectors =
|
||||
new double[currentSourcePastVectors.length][k + dimOfConditionals];
|
||||
MatrixUtils.arrayCopy(currentDestPastVectors, 0, 0,
|
||||
currentCombinedConditionalVectors, 0, 0,
|
||||
currentDestPastVectors.length, k);
|
||||
int nextColumnToCopyInto = k;
|
||||
for (int i = 0; i < condEmbedDims.length; i++) {
|
||||
// Extract the embedding for conditional variable i
|
||||
double[][] currentThisConditonalVectors =
|
||||
MatrixUtils.makeDelayEmbeddingVector(conditionals, i,
|
||||
condEmbedDims[i], this.cond_taus[i],
|
||||
startTimeForFirstDestEmbedding + 1 - condDelays[i],
|
||||
conditionals.length - startTimeForFirstDestEmbedding - 1);
|
||||
// And add this embedding to our set of conditional variables
|
||||
MatrixUtils.arrayCopy(currentThisConditonalVectors, 0, 0,
|
||||
currentCombinedConditionalVectors, 0, nextColumnToCopyInto,
|
||||
currentThisConditonalVectors.length, condEmbedDims[i]);
|
||||
nextColumnToCopyInto += condEmbedDims[i];
|
||||
}
|
||||
|
||||
double[][][] returnSet = new double[3][][];
|
||||
returnSet[0] = currentSourcePastVectors;
|
||||
returnSet[1] = currentDestNextVectors;
|
||||
returnSet[2] = currentCombinedConditionalVectors;
|
||||
return returnSet;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ConditionalTransferEntropyCalculator#addObservations(double[], double[], double[][], int, int)
|
||||
*/
|
||||
public void addObservations(double[] source, double[] destination,
|
||||
double[][] conditionals, int startTime, int numTimeSteps)
|
||||
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 (conditionals == null) {
|
||||
if (condEmbedDims.length > 0) {
|
||||
throw new Exception(String.format("No conditionals supplied (expected %d-dimensional conditionals", condEmbedDims.length));
|
||||
} else {
|
||||
// This is allowed; make a dummy set of conditionals
|
||||
conditionals = new double[destination.length][0];
|
||||
}
|
||||
}
|
||||
if (conditionals.length != destination.length) {
|
||||
throw new Exception(String.format("Conditionals and destination lengths (%d and %d) must match!",
|
||||
conditionals.length, destination.length));
|
||||
}
|
||||
// Postcondition -- all time series have same length
|
||||
if (source.length < startTime + numTimeSteps) {
|
||||
// There are not enough observations given the arguments here
|
||||
throw new Exception("Not enough observations to set here given startTime and numTimeSteps parameters");
|
||||
}
|
||||
addObservations(MatrixUtils.select(source, startTime, numTimeSteps),
|
||||
MatrixUtils.select(destination, startTime, numTimeSteps),
|
||||
MatrixUtils.selectRows(conditionals, startTime, numTimeSteps));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ConditionalTransferEntropyCalculator#addObservations(double[], double[], double[], int, int)
|
||||
*/
|
||||
public void addObservations(double[] source, double[] destination,
|
||||
double[] conditionals, int startTime, int numTimeSteps) throws Exception {
|
||||
if (condEmbedDims.length != 1) {
|
||||
throw new Exception("Cannot call addObservations(double[], double[], double[], int, int) when the " +
|
||||
"conditional TE calculator was not initialised for one conditional variable");
|
||||
}
|
||||
double[][] conditionalsIn2D = null;
|
||||
if (conditionals != null) {
|
||||
// This isn't incredibly efficient, but is easy to code and doesn't cost more
|
||||
// than an increase in the linear time multiplier.
|
||||
conditionalsIn2D = new double[conditionals.length][1];
|
||||
MatrixUtils.copyIntoColumn(conditionalsIn2D, 0, conditionals);
|
||||
}
|
||||
addObservations(source, destination, conditionalsIn2D, startTime, numTimeSteps);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ConditionalTransferEntropyCalculator#finaliseAddObservations()
|
||||
*/
|
||||
public void finaliseAddObservations() throws Exception {
|
||||
condMiCalc.finaliseAddObservations();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ConditionalTransferEntropyCalculator#setObservations(double[], double[], double[][], boolean[], boolean[], boolean[][])
|
||||
*/
|
||||
public void setObservations(double[] source, double[] destination,
|
||||
double[][] conditionals, boolean[] sourceValid,
|
||||
boolean[] destValid, boolean[][] conditionalsValid)
|
||||
throws Exception {
|
||||
|
||||
Vector<int[]> startAndEndTimePairs =
|
||||
computeStartAndEndTimePairs(sourceValid, destValid, conditionalsValid);
|
||||
|
||||
// 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, conditionals, startTime, endTime - startTime + 1);
|
||||
}
|
||||
finaliseAddObservations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a vector of start and end pairs of time points, between which we have
|
||||
* valid tuples of source, destinations and conditionals.
|
||||
* (i.e. all points within the
|
||||
* embedding vectors must be valid, even if the invalid points won't be included
|
||||
* in any tuples)
|
||||
*
|
||||
* Made public so it can be used if one wants to compute the number of
|
||||
* observations prior to setting the observations.
|
||||
*
|
||||
* @param sourceValid
|
||||
* @param destValid
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public Vector<int[]> computeStartAndEndTimePairs(boolean[] sourceValid,
|
||||
boolean[] destValid, boolean[][] condValid) throws Exception {
|
||||
|
||||
if (sourceValid.length != destValid.length) {
|
||||
throw new Exception("Validity arrays must be of same length");
|
||||
}
|
||||
if (condValid.length != destValid.length) {
|
||||
throw new Exception("Validity arrays must be of same length");
|
||||
}
|
||||
|
||||
int lengthOfDestPastRequired = (k-1)*k_tau + 1;
|
||||
int lengthOfSourcePastRequired = (l-1)*l_tau + 1;
|
||||
int[] lengthOfConditionalsPastsRequired = new int[condEmbedDims.length];
|
||||
for (int i = 0; i < condEmbedDims.length; i++) {
|
||||
lengthOfConditionalsPastsRequired[i] = (condEmbedDims[i]-1)*cond_taus[i] + 1;
|
||||
}
|
||||
|
||||
// Scan along the data avoiding invalid values
|
||||
int startTime = 0;
|
||||
Vector<int[]> startAndEndTimePairs = new Vector<int[]>();
|
||||
|
||||
// Simple solution -- this takes more complexity in time, but is
|
||||
// much faster to code:
|
||||
boolean previousWasOk = false;
|
||||
for (int t = startTimeForFirstDestEmbedding; t < destValid.length - 1; t++) {
|
||||
// Check the tuple with the history vector starting from
|
||||
// t and running backwards
|
||||
if (previousWasOk) {
|
||||
// Just check the very next values of each:
|
||||
boolean nextCondsValid = true;
|
||||
for (int i = 0; i < condEmbedDims.length; i++) {
|
||||
nextCondsValid &= condValid[t + 1 - condDelays[i]][i];
|
||||
}
|
||||
if (nextCondsValid && destValid[t + 1] && sourceValid[t + 1 - delay]) {
|
||||
// We can continue adding to this sequence
|
||||
continue;
|
||||
} else {
|
||||
// We need to shut down this sequence now
|
||||
previousWasOk = false;
|
||||
int[] timePair = new int[2];
|
||||
timePair[0] = startTime;
|
||||
timePair[1] = t; // Previous time step was last valid one
|
||||
startAndEndTimePairs.add(timePair);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Otherwise we're trying to start a new sequence, so check all values
|
||||
if (!destValid[t + 1]) {
|
||||
continue;
|
||||
}
|
||||
boolean allOk = true;
|
||||
for (int tBack = 0; tBack < lengthOfDestPastRequired; tBack++) {
|
||||
if (!destValid[t - tBack]) {
|
||||
allOk = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!allOk) {
|
||||
continue;
|
||||
}
|
||||
// allOk == true at this point
|
||||
for (int tBack = delay - 1; tBack < delay - 1 + lengthOfSourcePastRequired; tBack++) {
|
||||
if (!sourceValid[t - tBack]) {
|
||||
allOk = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!allOk) {
|
||||
continue;
|
||||
}
|
||||
// allOk == true at this point
|
||||
for (int i = 0; i < condEmbedDims.length; i++) {
|
||||
for (int tBack = condDelays[i] - 1; tBack < condDelays[i] - 1 + lengthOfConditionalsPastsRequired[i]; tBack++) {
|
||||
if (!condValid[t - tBack][i]) {
|
||||
allOk = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!allOk) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// allOk == true at this point
|
||||
// Postcondition: We've got a first valid tuple:
|
||||
startTime = t - startTimeForFirstDestEmbedding;
|
||||
previousWasOk = true;
|
||||
}
|
||||
// Now check if we were running a sequence and terminate it:
|
||||
if (previousWasOk) {
|
||||
// We need to shut down this sequence now
|
||||
previousWasOk = false;
|
||||
int[] timePair = new int[2];
|
||||
timePair[0] = startTime;
|
||||
timePair[1] = destValid.length - 1;
|
||||
startAndEndTimePairs.add(timePair);
|
||||
}
|
||||
|
||||
return startAndEndTimePairs;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ChannelCalculatorCommon#computeAverageLocalOfObservations()
|
||||
*/
|
||||
public double computeAverageLocalOfObservations() throws Exception {
|
||||
return condMiCalc.computeAverageLocalOfObservations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a time series of local conditional TE values.
|
||||
* Pads the first {@link #startTimeForFirstDestEmbedding} elements with zeros (since local TE is undefined here)
|
||||
* if only one time series of observations was used.
|
||||
* Otherwise, local values for all separate series are concatenated, and without
|
||||
* padding of zeros at the start.
|
||||
*
|
||||
* @return an array of local TE values of the previously submitted observations.
|
||||
*/
|
||||
public double[] computeLocalOfPreviousObservations() throws Exception {
|
||||
double[] local = condMiCalc.computeLocalOfPreviousObservations();
|
||||
if (!condMiCalc.getAddedMoreThanOneObservationSet()) {
|
||||
double[] localsToReturn = new double[local.length + startTimeForFirstDestEmbedding + 1];
|
||||
System.arraycopy(local, 0, localsToReturn, startTimeForFirstDestEmbedding + 1, local.length);
|
||||
return localsToReturn;
|
||||
} else {
|
||||
return local;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ConditionalTransferEntropyCalculator#computeLocalUsingPreviousObservations(double[], double[], double[][])
|
||||
*/
|
||||
public double[] computeLocalUsingPreviousObservations(
|
||||
double[] newSourceObservations, double[] newDestObservations,
|
||||
double[][] newCondObservations) throws Exception {
|
||||
|
||||
if (newSourceObservations.length != newDestObservations.length) {
|
||||
throw new Exception(String.format("Source and destination lengths (%d and %d) must match!",
|
||||
newSourceObservations.length, newDestObservations.length));
|
||||
}
|
||||
if (newCondObservations == null) {
|
||||
if (condEmbedDims.length > 0) {
|
||||
throw new Exception(String.format("No conditionals supplied (expected %d-dimensional conditionals)", condEmbedDims.length));
|
||||
} else {
|
||||
// This is allowed; make a dummy set of conditionals
|
||||
newCondObservations = new double[newDestObservations.length][0];
|
||||
}
|
||||
}
|
||||
if (newCondObservations.length != newDestObservations.length) {
|
||||
throw new Exception(String.format("Conditionals and destination lengths (%d and %d) must match!",
|
||||
newCondObservations.length, newDestObservations.length));
|
||||
}
|
||||
// Postcondition -- all time series have same length
|
||||
if (newCondObservations[0].length != condEmbedDims.length) {
|
||||
throw new Exception(String.format("Number of conditional variables %d does not " +
|
||||
"match the initialised number %d", newCondObservations[0].length, condEmbedDims.length));
|
||||
}
|
||||
if (newDestObservations.length < startTimeForFirstDestEmbedding + 2) {
|
||||
// There are no observations to compute for here
|
||||
return new double[newDestObservations.length];
|
||||
}
|
||||
// All parameters are as expected
|
||||
double[][][] embeddedVectorsForCondMI =
|
||||
embedSourceDestAndConditionalsForCondMI(newSourceObservations,
|
||||
newDestObservations, newCondObservations);
|
||||
|
||||
double[] local = condMiCalc.computeLocalUsingPreviousObservations(
|
||||
embeddedVectorsForCondMI[0], embeddedVectorsForCondMI[1],
|
||||
embeddedVectorsForCondMI[2]);
|
||||
// Pad the front of the array with zeros where local TE isn't defined:
|
||||
double[] localsToReturn = new double[local.length + startTimeForFirstDestEmbedding + 1];
|
||||
System.arraycopy(local, 0, localsToReturn, startTimeForFirstDestEmbedding + 1, local.length);
|
||||
return localsToReturn;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ConditionalTransferEntropyCalculator#computeLocalUsingPreviousObservations(double[], double[], double[])
|
||||
*/
|
||||
public double[] computeLocalUsingPreviousObservations(
|
||||
double[] newSourceObservations, double[] newDestObservations,
|
||||
double[] newCondObservations) throws Exception {
|
||||
|
||||
if (condEmbedDims.length != 1) {
|
||||
throw new Exception("Cannot call computeLocalUsingPreviousObservations(double[], double[], double[]) when the " +
|
||||
"conditional TE calculator was not initialised for one conditional variable");
|
||||
}
|
||||
double[][] conditionalsIn2D = null;
|
||||
if (newCondObservations != null) {
|
||||
// This isn't incredibly efficient, but is easy to code and doesn't cost more
|
||||
// than an increase in the linear time multiplier.
|
||||
conditionalsIn2D = new double[newCondObservations.length][1];
|
||||
MatrixUtils.copyIntoColumn(conditionalsIn2D, 0, newCondObservations);
|
||||
}
|
||||
return computeLocalUsingPreviousObservations(newSourceObservations,
|
||||
newDestObservations, conditionalsIn2D);
|
||||
}
|
||||
|
||||
public EmpiricalMeasurementDistribution computeSignificance(
|
||||
int numPermutationsToCheck) throws Exception {
|
||||
return condMiCalc.computeSignificance(1, numPermutationsToCheck); // Reorder the source vectors
|
||||
}
|
||||
|
||||
public EmpiricalMeasurementDistribution computeSignificance(
|
||||
int[][] newOrderings) throws Exception {
|
||||
return condMiCalc.computeSignificance(1, newOrderings); // Reorder the source vectors
|
||||
}
|
||||
|
||||
public double getLastAverage() {
|
||||
return condMiCalc.getLastAverage();
|
||||
}
|
||||
|
||||
public int getNumObservations() throws Exception {
|
||||
return condMiCalc.getNumObservations();
|
||||
}
|
||||
|
||||
public boolean getAddedMoreThanOneObservationSet() {
|
||||
return condMiCalc.getAddedMoreThanOneObservationSet();
|
||||
}
|
||||
|
||||
public void setDebug(boolean debug) {
|
||||
this.debug = debug;
|
||||
condMiCalc.setDebug(debug);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,18 +8,20 @@ public interface EntropyCalculator {
|
|||
*/
|
||||
public void initialise() throws Exception;
|
||||
|
||||
public void setObservations(double observations[]);
|
||||
|
||||
public double computeAverageLocalOfObservations();
|
||||
|
||||
public void setDebug(boolean debug);
|
||||
|
||||
/**
|
||||
* Allows the user to set properties for the underlying calculator implementation
|
||||
* New property values are not guaranteed to take effect until the next call
|
||||
* to an initialise method.
|
||||
*
|
||||
* @param propertyName
|
||||
* @param propertyValue
|
||||
* @throws Exception
|
||||
*/
|
||||
public void setProperty(String propertyName, String propertyValue) throws Exception;
|
||||
|
||||
public void setObservations(double observations[]);
|
||||
|
||||
public double computeAverageLocalOfObservations();
|
||||
|
||||
public void setDebug(boolean debug);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,17 @@ public interface EntropyCalculatorMultiVariate {
|
|||
|
||||
public void initialise(int dimensions);
|
||||
|
||||
/**
|
||||
* Allows the user to set properties for the underlying calculator implementation
|
||||
* New property values are not guaranteed to take effect until the next call
|
||||
* to an initialise method.
|
||||
*
|
||||
* @param propertyName
|
||||
* @param propertyValue
|
||||
* @throws Exception
|
||||
*/
|
||||
public void setProperty(String propertyName, String propertyValue) throws Exception;
|
||||
|
||||
/**
|
||||
* Supply the observations for which to compute the PDFs for the entropy
|
||||
*
|
||||
|
|
|
|||
|
|
@ -42,7 +42,10 @@ public interface MutualInfoCalculatorMultiVariateWithDiscrete {
|
|||
public void initialise(int dimensions, int base) throws Exception;
|
||||
|
||||
/**
|
||||
* <p>Set the required property of the calculator to the given value.</p>
|
||||
* <p>Set the required property of the calculator to the given value.
|
||||
* New property values are not guaranteed to take effect until the next call
|
||||
* to an initialise method.
|
||||
* </p>
|
||||
*
|
||||
* <p>There are no general properties settable on all child classes;
|
||||
* each child class may define their own properties.</p>
|
||||
|
|
|
|||
|
|
@ -84,6 +84,13 @@ public abstract class MutualInfoMultiVariateCommon implements
|
|||
|
||||
protected boolean addedMoreThanOneObservationSet;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ChannelCalculatorCommon#initialise()
|
||||
*/
|
||||
public void initialise() throws Exception {
|
||||
initialise(dimensionsSource, dimensionsDest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear any previously supplied probability distributions and prepare
|
||||
* the calculator to be used again.
|
||||
|
|
@ -103,6 +110,8 @@ public abstract class MutualInfoMultiVariateCommon implements
|
|||
|
||||
/**
|
||||
* <p>Set the given property to the given value.
|
||||
* New property values are not guaranteed to take effect until the next call
|
||||
* to an initialise method.
|
||||
* These can include:
|
||||
* <ul>
|
||||
* <li>{@link MutualInfoCalculatorMultiVariate#PROP_TIME_DIFF}</li>
|
||||
|
|
|
|||
|
|
@ -35,11 +35,16 @@ import infodynamics.utils.MatrixUtils;
|
|||
* <a href='http://dx.doi.org/10.1007/s10827-010-0271-2'>download</a>
|
||||
* (for definition of <i>multivariate</i> transfer entropy"
|
||||
*
|
||||
* @see {@link TransferEntropyCalculatorViaCondMutualInfo}
|
||||
* @see {@link TransferEntropyCalculatorMultiVariate}
|
||||
* @see {@link TransferEntropyCalculator}
|
||||
*
|
||||
* @author Joseph Lizier, <a href="joseph.lizier at gmail.com">email</a>,
|
||||
* <a href="http://lizier.me/joseph/">www</a>
|
||||
*/
|
||||
public abstract class TransferEntropyCalculatorMultiVariateViaCondMutualInfo
|
||||
extends TransferEntropyCalculatorViaCondMutualInfo
|
||||
// which means we implement TransferEntropyCalculator
|
||||
implements TransferEntropyCalculatorMultiVariate {
|
||||
|
||||
/**
|
||||
|
|
@ -66,8 +71,9 @@ public abstract class TransferEntropyCalculatorMultiVariateViaCondMutualInfo
|
|||
* underlying Conditional Mutual information calculator.
|
||||
*
|
||||
* @param condMiCalc
|
||||
* @throws Exception
|
||||
*/
|
||||
public TransferEntropyCalculatorMultiVariateViaCondMutualInfo(ConditionalMutualInfoCalculatorMultiVariate condMiCalc) {
|
||||
public TransferEntropyCalculatorMultiVariateViaCondMutualInfo(ConditionalMutualInfoCalculatorMultiVariate condMiCalc) throws Exception {
|
||||
super(condMiCalc);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ public abstract class TransferEntropyCalculatorViaCondMutualInfo implements
|
|||
*/
|
||||
public static final String K_TAU_PROP_NAME = "k_TAU";
|
||||
/**
|
||||
* Embedding delay for the destination past history vector
|
||||
* Embedding length for the source past history vector
|
||||
*/
|
||||
public static final String L_PROP_NAME = "l_HISTORY";
|
||||
/**
|
||||
|
|
@ -85,8 +85,18 @@ public abstract class TransferEntropyCalculatorViaCondMutualInfo implements
|
|||
* Source-destination delay
|
||||
*/
|
||||
public static final String DELAY_PROP_NAME = "DELAY";
|
||||
|
||||
|
||||
/**
|
||||
* Construct a transfer entropy calculator using an instance of
|
||||
* condMiCalculatorClassName as the underlying conditional mutual information calculator.
|
||||
*
|
||||
* @param condMiCalculatorClassName name of the class which must implement
|
||||
* {@link ConditionalMutualInfoCalculatorMultiVariate}
|
||||
* @throws InstantiationException if the given class cannot be instantiated
|
||||
* @throws IllegalAccessException if illegal access occurs while trying to create an instance
|
||||
* of the class
|
||||
* @throws ClassNotFoundException if the given class is not found
|
||||
*/
|
||||
public TransferEntropyCalculatorViaCondMutualInfo(String condMiCalculatorClassName)
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
@ -96,6 +106,17 @@ public abstract class TransferEntropyCalculatorViaCondMutualInfo implements
|
|||
construct(condMiCalc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a transfer entropy calculator using an instance of
|
||||
* condMiCalcClass as the underlying conditional mutual information calculator.
|
||||
*
|
||||
* @param condMiCalcClass the class which must implement
|
||||
* {@link ConditionalMutualInfoCalculatorMultiVariate}
|
||||
* @throws InstantiationException if the given class cannot be instantiated
|
||||
* @throws IllegalAccessException if illegal access occurs while trying to create an instance
|
||||
* of the class
|
||||
* @throws ClassNotFoundException if the given class is not found
|
||||
*/
|
||||
public TransferEntropyCalculatorViaCondMutualInfo(Class<ConditionalMutualInfoCalculatorMultiVariate> condMiCalcClass)
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
|
||||
ConditionalMutualInfoCalculatorMultiVariate condMiCalc = condMiCalcClass.newInstance();
|
||||
|
|
@ -106,16 +127,30 @@ public abstract class TransferEntropyCalculatorViaCondMutualInfo implements
|
|||
* Construct this calculator by passing in a constructed but not initialised
|
||||
* underlying Conditional Mutual information calculator.
|
||||
*
|
||||
* @param condMiCalc
|
||||
* @param condMiCalc An instantiated conditional mutual information calculator.
|
||||
* @throws Exception if the supplied calculator has not yet been instantiated.
|
||||
*/
|
||||
public TransferEntropyCalculatorViaCondMutualInfo(ConditionalMutualInfoCalculatorMultiVariate condMiCalc) {
|
||||
public TransferEntropyCalculatorViaCondMutualInfo(ConditionalMutualInfoCalculatorMultiVariate condMiCalc) throws Exception {
|
||||
if (condMiCalc == null) {
|
||||
throw new Exception("Conditional MI calculator used to construct ConditionalTransferEntropyCalculatorViaCondMutualInfo " +
|
||||
" must have already been instantiated.");
|
||||
}
|
||||
construct(condMiCalc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to set the conditional mutual information calculator.
|
||||
* Can be overridden if anything else needs to be done with it by the child classes.
|
||||
*
|
||||
* @param condMiCalc
|
||||
*/
|
||||
protected void construct(ConditionalMutualInfoCalculatorMultiVariate condMiCalc) {
|
||||
this.condMiCalc = condMiCalc;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.ChannelCalculatorCommon#initialise()
|
||||
*/
|
||||
public void initialise() throws Exception {
|
||||
initialise(k, k_tau, l, l_tau, delay);
|
||||
}
|
||||
|
|
@ -158,10 +193,13 @@ public abstract class TransferEntropyCalculatorViaCondMutualInfo implements
|
|||
|
||||
/**
|
||||
* <p>Set the given property to the given value.
|
||||
* New property values are not guaranteed to take effect until the next call
|
||||
* to an initialise method.
|
||||
* These can include:
|
||||
* <ul>
|
||||
* <li>{@link #K_PROP_NAME}</li>
|
||||
* <li>{@link #K_TAU_PROP_NAME}</li>
|
||||
* <li>{@link #L_PROP_NAME}</li>
|
||||
* <li>{@link #L_TAU_PROP_NAME}</li>
|
||||
* <li>{@link #DELAY_PROP_NAME}</li>
|
||||
* </ul>
|
||||
|
|
@ -296,7 +334,9 @@ public abstract class TransferEntropyCalculatorViaCondMutualInfo implements
|
|||
|
||||
/**
|
||||
* Compute a vector of start and end pairs of time points, between which we have
|
||||
* valid series of both source and destinations.
|
||||
* valid series of both source and destinations. (i.e. all points within the
|
||||
* embedding vectors must be valid, even if the invalid points won't be included
|
||||
* in any tuples)
|
||||
*
|
||||
* Made public so it can be used if one wants to compute the number of
|
||||
* observations prior to setting the observations.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
package infodynamics.measures.continuous.gaussian;
|
||||
|
||||
import infodynamics.measures.continuous.ConditionalTransferEntropyCalculatorViaCondMutualInfo;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>
|
||||
* Implements a conditional transfer entropy calculator using model of
|
||||
* Gaussian variables with linear interactions.
|
||||
* This is equivalent (up to a multiplicative constant) to
|
||||
* (a conditional) Granger causality (see Barnett et al., below).
|
||||
* This is achieved by plugging in {@link ConditionalMutualInfoCalculatorMultiVariateGaussian}
|
||||
* as the calculator into {@link ConditionalTransferEntropyCalculatorViaCondMutualInfo}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Usage:
|
||||
* <ol>
|
||||
* <li>Construct: {@link #ConditionalTransferEntropyCalculatorGaussian()}</li>
|
||||
* <li>Set properties: {@link #setProperty(String, String)} for each relevant property, including those
|
||||
* of either {@link ConditionalTransferEntropyCalculatorViaCondMutualInfo#setProperty(String, String)}
|
||||
* or {@link ConditionalMutualInfoCalculatorMultiVariateGaussian#setProperty(String, String)}.</li>
|
||||
* <li>Initialise: by calling one of {@link #initialise()} etc.</li>
|
||||
* <li>Add observations to construct the PDFs: {@link #setObservations(double[], double[], double[][])},
|
||||
* or [{@link #startAddObservations()},
|
||||
* {@link #addObservations(double[], double[], double[][])}*, {@link #finaliseAddObservations()}]
|
||||
* Note: If not using setObservations(), the results from computeLocal
|
||||
* will be concatenated directly, and getSignificance will mix up observations
|
||||
* from separate trials (added in separate {@link #addObservations(double[])} calls.</li>
|
||||
* <li>Compute measures: e.g. {@link #computeAverageLocalOfObservations()} or
|
||||
* {@link #computeLocalOfPreviousObservations()} etc </li>
|
||||
* </ol>
|
||||
* </p>
|
||||
*
|
||||
* @author Joseph Lizier, <a href="joseph.lizier at gmail.com">email</a>,
|
||||
* <a href="http://lizier.me/joseph/">www</a>
|
||||
*
|
||||
* @see "Schreiber, Physical Review Letters 85 (2) pp.461-464 (2000);
|
||||
* <a href='http://dx.doi.org/10.1103/PhysRevLett.85.461'>download</a>
|
||||
* (for definition of transfer entropy)"
|
||||
* @see "Lizier, Prokopenko and Zomaya, Physical Review E 77, 026110 (2008);
|
||||
* <a href='http://dx.doi.org/10.1103/PhysRevE.77.026110'>download</a>
|
||||
* (for the extension to <i>conditional</i> transfer entropy
|
||||
* or <i>complete</i> where all other causal sources are conditioned on,
|
||||
* and <i>local</i> transfer entropy)"
|
||||
* @see "Lizier, Prokopenko and Zomaya, Chaos 20, 3, 037109 (2010);
|
||||
* <a href='http://dx.doi.org/10.1063/1.3486801'>download</a>
|
||||
* (for further clarification on <i>conditional</i> transfer entropy
|
||||
* or <i>complete</i> where all other causal sources are conditioned on)"
|
||||
* @see "Lionel Barnett, Adam B. Barrett, Anil K. Seth, Physical Review Letters 103 (23) 238701, 2009;
|
||||
* <a href='http://dx.doi.org/10.1103/physrevlett.103.238701'>download</a>
|
||||
* (for direct relation between transfer entropy and Granger causality)"
|
||||
*
|
||||
* @see ConditionalTransferEntropyCalculator
|
||||
*
|
||||
*/
|
||||
public class ConditionalTransferEntropyCalculatorGaussian
|
||||
extends ConditionalTransferEntropyCalculatorViaCondMutualInfo {
|
||||
|
||||
public static final String COND_MI_CALCULATOR_GAUSSIAN = ConditionalMutualInfoCalculatorMultiVariateGaussian.class.getName();
|
||||
|
||||
/**
|
||||
* Creates a new instance of the Gaussian-estimate style conditional transfer entropy calculator
|
||||
* @throws ClassNotFoundException
|
||||
* @throws IllegalAccessException
|
||||
* @throws InstantiationException
|
||||
*
|
||||
*/
|
||||
public ConditionalTransferEntropyCalculatorGaussian() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
|
||||
super(COND_MI_CALCULATOR_GAUSSIAN);
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ import java.util.Vector;
|
|||
/**
|
||||
*
|
||||
* <p>
|
||||
* Implements a transfer entropy calculator using kernel estimation.
|
||||
* Implements a multivariate transfer entropy calculator using kernel estimation.
|
||||
* (see Schreiber, PRL 85 (2) pp.461-464, 2000)</p>
|
||||
*
|
||||
* <p>
|
||||
|
|
|
|||
|
|
@ -52,6 +52,14 @@ public class EntropyCalculatorMultiVariateKozachenko
|
|||
isComputed = false;
|
||||
lastLocalEntropy = null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.EntropyCalculatorMultiVariate#setProperty(java.lang.String, java.lang.String)
|
||||
*/
|
||||
public void setProperty(String propertyName, String propertyValue)
|
||||
throws Exception {
|
||||
// No properties here to set
|
||||
}
|
||||
|
||||
public void setObservations(double[][] observations) {
|
||||
rawData = observations;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,186 @@
|
|||
package infodynamics.measures.continuous.kraskov;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import infodynamics.measures.continuous.ConditionalMutualInfoCalculatorMultiVariate;
|
||||
import infodynamics.measures.continuous.ConditionalTransferEntropyCalculator;
|
||||
import infodynamics.measures.continuous.ConditionalTransferEntropyCalculatorViaCondMutualInfo;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>
|
||||
* Implements a conditional transfer entropy calculator using a conditional MI calculator
|
||||
* implementing the Kraskov-Grassberger estimator.
|
||||
* This is achieved by plugging in a {@link ConditionalMutualInfoCalculatorMultiVariateKraskov}
|
||||
* as the calculator into {@link TransferEntropyCalculatorViaCondMutualInfo}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Usage:
|
||||
* <ol>
|
||||
* <li>Construct: {@link #ConditionalTransferEntropyCalculatorKraskov()}</li>
|
||||
* <li>Set properties: {@link #setProperty(String, String)} for each relevant property, including those
|
||||
* of either {@link ConditionalTransferEntropyCalculatorViaCondMutualInfo#setProperty(String, String)}
|
||||
* or {@link ConditionalMutualInfoCalculatorMultiVariateKraskov#setProperty(String, String)}.</li>
|
||||
* <li>Initialise: by calling one of {@link #initialise()} etc.</li>
|
||||
* <li>Add observations to construct the PDFs: {@link #setObservations(double[], double[], double[][])},
|
||||
* or [{@link #startAddObservations()},
|
||||
* {@link #addObservations(double[])}*, {@link #finaliseAddObservations()}]
|
||||
* Note: If not using setObservations(), the results from computeLocal
|
||||
* will be concatenated directly, and getSignificance will mix up observations
|
||||
* from separate trials (added in separate {@link #addObservations(double[])} calls.</li>
|
||||
* <li>Compute measures: e.g. {@link #computeAverageLocalOfObservations()} or
|
||||
* {@link #computeLocalOfPreviousObservations()} etc </li>
|
||||
* </ol>
|
||||
* </p>
|
||||
*
|
||||
* @author Joseph Lizier, <a href="joseph.lizier at gmail.com">email</a>,
|
||||
* <a href="http://lizier.me/joseph/">www</a>
|
||||
*
|
||||
* @see "Schreiber, Physical Review Letters 85 (2) pp.461-464 (2000);
|
||||
* <a href='http://dx.doi.org/10.1103/PhysRevLett.85.461'>download</a>
|
||||
* (for definition of transfer entropy)"
|
||||
* @see "Lizier, Prokopenko and Zomaya, Physical Review E 77, 026110 (2008);
|
||||
* <a href='http://dx.doi.org/10.1103/PhysRevE.77.026110'>download</a>
|
||||
* (for the extension to <i>conditional</i> transfer entropy
|
||||
* or <i>complete</i> where all other causal sources are conditioned on,
|
||||
* and <i>local</i> transfer entropy)"
|
||||
* @see "Lizier, Prokopenko and Zomaya, Chaos 20, 3, 037109 (2010);
|
||||
* <a href='http://dx.doi.org/10.1063/1.3486801'>download</a>
|
||||
* (for further clarification on <i>conditional</i> transfer entropy
|
||||
* or <i>complete</i> where all other causal sources are conditioned on)"
|
||||
* @see "Kraskov, A., Stoegbauer, H., Grassberger, P., Physical Review E 69, (2004) 066138;
|
||||
* <a href='http://dx.doi.org/10.1103/PhysRevE.69.066138'>download</a>
|
||||
* (for introduction of Kraskov-Grassberger method for MI)"
|
||||
* @see "G. Gomez-Herrero, W. Wu, K. Rutanen, M. C. Soriano, G. Pipa, and R. Vicente,
|
||||
* arXiv:1008.0539, 2010;
|
||||
* <a href='http://arxiv.org/abs/1008.0539'>download</a>
|
||||
* (for introduction of Kraskov-Grassberger technique to transfer entropy)"
|
||||
* @see ConditionalTransferEntropyCalculator
|
||||
*
|
||||
*/
|
||||
public class ConditionalTransferEntropyCalculatorKraskov
|
||||
extends ConditionalTransferEntropyCalculatorViaCondMutualInfo {
|
||||
|
||||
public static final String COND_MI_CALCULATOR_KRASKOV1 = ConditionalMutualInfoCalculatorMultiVariateKraskov1.class.getName();
|
||||
public static final String COND_MI_CALCULATOR_KRASKOV2 = ConditionalMutualInfoCalculatorMultiVariateKraskov2.class.getName();
|
||||
|
||||
/**
|
||||
* Property for setting which underlying Kraskov-Grassberger algorithm to use.
|
||||
* Will only be applied at the next initialisation.
|
||||
*/
|
||||
public final static String PROP_KRASKOV_ALG_NUM = "ALG_NUM";
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the Kraskov-estimate style conditional transfer entropy calculator
|
||||
*
|
||||
* Uses algorithm 1 by default, as per Gomez-Herro et al.
|
||||
*
|
||||
* @throws ClassNotFoundException
|
||||
* @throws IllegalAccessException
|
||||
* @throws InstantiationException
|
||||
*
|
||||
*/
|
||||
public ConditionalTransferEntropyCalculatorKraskov() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
|
||||
super(COND_MI_CALCULATOR_KRASKOV1);
|
||||
kraskovAlgorithmNumber = 1;
|
||||
props = new Hashtable<String,String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of the Kraskov-Grassberger style conditional transfer entropy calculator,
|
||||
* with the supplied conditional MI calculator name
|
||||
*
|
||||
* @param calculatorName fully qualified name of the underlying MI class.
|
||||
* Must be {@link #COND_MI_CALCULATOR_KRASKOV1} or {@link #COND_MI_CALCULATOR_KRASKOV2}
|
||||
* @throws ClassNotFoundException
|
||||
* @throws IllegalAccessException
|
||||
* @throws InstantiationException
|
||||
*
|
||||
*/
|
||||
public ConditionalTransferEntropyCalculatorKraskov(String calculatorName) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
|
||||
super(calculatorName);
|
||||
// Now check that it was one of our Kraskov-Grassberger calculators:
|
||||
if (calculatorName.equalsIgnoreCase(COND_MI_CALCULATOR_KRASKOV1)) {
|
||||
kraskovAlgorithmNumber = 1;
|
||||
} else if (calculatorName.equalsIgnoreCase(COND_MI_CALCULATOR_KRASKOV2)) {
|
||||
kraskovAlgorithmNumber = 2;
|
||||
} else {
|
||||
throw new ClassNotFoundException("Must be an underlying Kraskov-Grassberger conditional MI calculator");
|
||||
}
|
||||
props = new Hashtable<String,String>();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see infodynamics.measures.continuous.TransferEntropyCalculatorViaCondMutualInfo#initialise(int, int, int, int, int)
|
||||
*/
|
||||
@Override
|
||||
public void initialise(int k, int k_tau, int l, int l_tau, int delay,
|
||||
int[] condEmbedDims, int[] cond_taus, int[] condDelays)
|
||||
throws Exception {
|
||||
if (algChanged) {
|
||||
// The algorithm number was changed in a setProperties call:
|
||||
String newCalcName = COND_MI_CALCULATOR_KRASKOV1;
|
||||
if (kraskovAlgorithmNumber == 2) {
|
||||
newCalcName = COND_MI_CALCULATOR_KRASKOV2;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<ConditionalMutualInfoCalculatorMultiVariate> condMiClass =
|
||||
(Class<ConditionalMutualInfoCalculatorMultiVariate>) Class.forName(newCalcName);
|
||||
ConditionalMutualInfoCalculatorMultiVariate newCondMiCalc = condMiClass.newInstance();
|
||||
construct(newCondMiCalc);
|
||||
// Set the properties for the Kraskov MI calculators (may pass in properties for our super class
|
||||
// as well, but they should be ignored)
|
||||
for (String key : props.keySet()) {
|
||||
newCondMiCalc.setProperty(key, props.get(key));
|
||||
}
|
||||
algChanged = false;
|
||||
}
|
||||
|
||||
super.initialise(k, k_tau, l, l_tau, delay, condEmbedDims, cond_taus, condDelays);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets properties for the calculator.
|
||||
* Valid properties include:
|
||||
* <ul>
|
||||
* <li>{@link #PROP_KRASKOV_ALG_NUM} - which Kraskov algorithm number to use (1 or 2). Will only be applied at the next initialisation.</li>
|
||||
* <li>Any valid properties for {@link ConditionalTransferEntropyCalculatorViaCondMutualInfo#setProperty(String, String)}</li>
|
||||
* <li>Any valid properties for {@link ConditionalMutualInfoCalculatorMultiVariateKraskov#setProperty(String, String)}</li>
|
||||
* </ul>
|
||||
* One should set {@link ConditionalMutualInfoCalculatorMultiVariateKraskov#PROP_K} here, the number
|
||||
* of neighbouring points one should count up to in determining the joint kernel size.
|
||||
*
|
||||
* @param propertyName name of the property
|
||||
* @param propertyValue value of the property (as a string)
|
||||
*/
|
||||
public void setProperty(String propertyName, String propertyValue)
|
||||
throws Exception {
|
||||
if (propertyName.equalsIgnoreCase(PROP_KRASKOV_ALG_NUM)) {
|
||||
int previousAlgNumber = kraskovAlgorithmNumber;
|
||||
kraskovAlgorithmNumber = Integer.parseInt(propertyValue);
|
||||
if ((kraskovAlgorithmNumber != 1) && (kraskovAlgorithmNumber != 2)) {
|
||||
throw new Exception("Kraskov algorithm number (" + kraskovAlgorithmNumber
|
||||
+ ") must be either 1 or 2");
|
||||
}
|
||||
if (kraskovAlgorithmNumber != previousAlgNumber) {
|
||||
algChanged = true;
|
||||
}
|
||||
if (debug) {
|
||||
System.out.println(this.getClass().getSimpleName() + ": Set property " + propertyName +
|
||||
" to " + propertyValue);
|
||||
}
|
||||
} 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@ import java.util.Hashtable;
|
|||
import infodynamics.measures.continuous.ConditionalMutualInfoCalculatorMultiVariate;
|
||||
import infodynamics.measures.continuous.TransferEntropyCalculator;
|
||||
import infodynamics.measures.continuous.TransferEntropyCalculatorViaCondMutualInfo;
|
||||
import infodynamics.measures.continuous.gaussian.ConditionalMutualInfoCalculatorMultiVariateGaussian;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -22,7 +21,7 @@ import infodynamics.measures.continuous.gaussian.ConditionalMutualInfoCalculator
|
|||
* <li>Construct: {@link #TransferEntropyCalculatorKraskov()}</li>
|
||||
* <li>Set properties: {@link #setProperty(String, String)} for each relevant property, including those
|
||||
* of either {@link TransferEntropyCalculatorViaCondMutualInfo#setProperty(String, String)}
|
||||
* or {@link ConditionalMutualInfoCalculatorMultiVariateGaussian#setProperty(String, String)}.</li>
|
||||
* or {@link ConditionalMutualInfoCalculatorMultiVariateKraskov#setProperty(String, String)}.</li>
|
||||
* <li>Initialise: by calling one of {@link #initialise()} etc.</li>
|
||||
* <li>Add observations to construct the PDFs: {@link #setObservations(double[])}, or [{@link #startAddObservations()},
|
||||
* {@link #addObservations(double[])}*, {@link #finaliseAddObservations()}]
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ import java.util.Comparator;
|
|||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Utilities for computations on matrices, represented as two-dimensional
|
||||
* Utilities for computations on arrays and matrices of data.
|
||||
* Matrices are represented as two-dimensional
|
||||
* arrays of doubles (double[][] matrix) - it is assumed that all
|
||||
* multidimensional matrices have consistent lengths in each dimension
|
||||
* matrix[i].
|
||||
|
|
@ -1617,11 +1618,11 @@ public class MatrixUtils {
|
|||
|
||||
/**
|
||||
* Constructs all embedding vectors of size k for the data.
|
||||
* Will be data.length - k + 1 of these
|
||||
* There will be (data.length - k + 1) of these vectors returned.
|
||||
*
|
||||
* @param data
|
||||
* @param k
|
||||
* @return
|
||||
* @param data time series data
|
||||
* @param k embedding length
|
||||
* @return An array of k-length embedding vectors
|
||||
*/
|
||||
public static double[][] makeDelayEmbeddingVector(double[] data, int k) {
|
||||
try {
|
||||
|
|
@ -1637,11 +1638,14 @@ public class MatrixUtils {
|
|||
* Constructs numEmbeddingVectors embedding vectors of size k for the data,
|
||||
* with the first embedding vector having it's last time point at t=startKthPoint
|
||||
*
|
||||
* @param data
|
||||
* @param k
|
||||
* @param startKthPoint
|
||||
* @param numEmbeddingVectors
|
||||
* @return
|
||||
* @param data time series data
|
||||
* @param k embedding length
|
||||
* @param startKthPoint last time point of the first embedding vector
|
||||
* (i.e. use k-1 if you want to go from the start)
|
||||
* @param numEmbeddingVectors the number of embedding vectors to return
|
||||
* (i.e. use data.length-k+1 if you go from the start and want all
|
||||
* of them extracted)
|
||||
* @return a 2D array of k-length embedding vectors.
|
||||
*/
|
||||
public static double[][] makeDelayEmbeddingVector(double[] data, int k,
|
||||
int startKthPoint, int numEmbeddingVectors) throws Exception {
|
||||
|
|
@ -1665,15 +1669,19 @@ public class MatrixUtils {
|
|||
|
||||
/**
|
||||
* Constructs numEmbeddingVectors embedding vectors of size k for the data,
|
||||
* with embedding delay tau between each element of the vectors,
|
||||
* with embedding delay tau between each time sample for the vectors,
|
||||
* with the first embedding vector having it's last time point at t=startKthPoint
|
||||
*
|
||||
* @param data
|
||||
* @param k
|
||||
* @param tau
|
||||
* @param startKthPoint
|
||||
* @param numEmbeddingVectors
|
||||
* @return
|
||||
* @param data time series data
|
||||
* @param k embedding length
|
||||
* @param tau embedding delay between each point in the original time series
|
||||
* selected into each embedding vector
|
||||
* @param startKthPoint last time point of the first embedding vector
|
||||
* (i.e. use k-1 if you want to go from the start)
|
||||
* @param numEmbeddingVectors the number of embedding vectors to return
|
||||
* (i.e. use data.length-k+1 if you go from the start and want all
|
||||
* of them extracted)
|
||||
* @return a 2D array of k-length embedding vectors.
|
||||
*/
|
||||
public static double[][] makeDelayEmbeddingVector(double[] data, int k, int tau,
|
||||
int startKthPoint, int numEmbeddingVectors) throws Exception {
|
||||
|
|
@ -1696,12 +1704,15 @@ public class MatrixUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructs all embedding vectors of size k for the data.
|
||||
* Will be data.length - k + 1 of these
|
||||
* Constructs all embedding vectors of k time points for the data, including
|
||||
* all multivariate values at each time point.
|
||||
* Will be data.length - k + 1 of these vectors returned
|
||||
*
|
||||
* @param data
|
||||
* @param k
|
||||
* @return
|
||||
* @param data 2D time series data (time is first second, second is variable number),
|
||||
* all of which is embedded
|
||||
* @param k embedding length (i.e. number of time extractions for each vector)
|
||||
* @return a 2D array of embedding vectors, which are of length
|
||||
* k x data[0].length.
|
||||
*/
|
||||
public static double[][] makeDelayEmbeddingVector(double[][] data, int k) {
|
||||
try {
|
||||
|
|
@ -1714,14 +1725,20 @@ public class MatrixUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructs numEmbeddingVectors embedding vectors of size k for the data,
|
||||
* with the first embedding vector having it's last time point at t=startKthPoint
|
||||
* Constructs numEmbeddingVectors embedding vectors of k time points for the data, including
|
||||
* all multivariate values at each time point.
|
||||
* Return only a subset, with the first embedding vector having it's last time point at t=startKthPoint
|
||||
*
|
||||
* @param data
|
||||
* @param k
|
||||
* @param startKthPoint
|
||||
* @param numEmbeddingVectors
|
||||
* @return
|
||||
* @param data 2D time series data (time is first second, second is variable number),
|
||||
* all of which is embedded
|
||||
* @param k embedding length (i.e. number of time extractions for each vector)
|
||||
* @param startKthPoint last time point of the first embedding vector
|
||||
* (i.e. use k-1 if you want to go from the start)
|
||||
* @param numEmbeddingVectors the number of embedding vectors to return
|
||||
* (i.e. use data.length-k+1 if you go from the start and want all
|
||||
* of them extracted)
|
||||
* @return a 2D array of embedding vectors, which are each of length
|
||||
* k x data[0].length.
|
||||
*/
|
||||
public static double[][] makeDelayEmbeddingVector(double[][] data, int k,
|
||||
int startKthPoint, int numEmbeddingVectors) throws Exception {
|
||||
|
|
@ -1747,16 +1764,23 @@ public class MatrixUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructs numEmbeddingVectors embedding vectors of size k for the data,
|
||||
* with embedding delay tau between each element of the vectors,
|
||||
* Constructs numEmbeddingVectors embedding vectors of k time points for the data, including
|
||||
* all multivariate values at each time point,
|
||||
* with embedding delay tau between each time sample for the vectors,
|
||||
* with the first embedding vector having it's last time point at t=startKthPoint
|
||||
*
|
||||
* @param data
|
||||
* @param k
|
||||
* @param tau
|
||||
* @param startKthPoint
|
||||
* @param numEmbeddingVectors
|
||||
* @return
|
||||
* @param data 2D time series data (time is first second, second is variable number),
|
||||
* all of which is embedded
|
||||
* @param k embedding length (i.e. number of time extractions for each vector)
|
||||
* @param tau embedding delay between each point in the original time series
|
||||
* selected into each embedding vector
|
||||
* @param startKthPoint last time point of the first embedding vector
|
||||
* (i.e. use k-1 if you want to go from the start)
|
||||
* @param numEmbeddingVectors the number of embedding vectors to return
|
||||
* (i.e. use data.length-k+1 if you go from the start and want all
|
||||
* of them extracted)
|
||||
* @return a 2D array of numEmbeddingVectors embedding vectors, which are each of length
|
||||
* k x data[0].length.
|
||||
*/
|
||||
public static double[][] makeDelayEmbeddingVector(double[][] data, int k, int tau,
|
||||
int startKthPoint, int numEmbeddingVectors) throws Exception {
|
||||
|
|
@ -1781,14 +1805,45 @@ public class MatrixUtils {
|
|||
return embeddingVectors;
|
||||
}
|
||||
|
||||
public static int[] subArray(int[] array, int startIndex, int theLength) {
|
||||
int[] sub = new int[theLength];
|
||||
for (int r = 0; r < theLength; r++) {
|
||||
sub[r] = array[startIndex + r];
|
||||
/**
|
||||
* Constructs numEmbeddingVectors embedding vectors of k time points for a single column of
|
||||
* the data,
|
||||
* with embedding delay tau between each time sample for the vectors,
|
||||
* with the first embedding vector having it's last time point at t=startKthPoint
|
||||
*
|
||||
* @param data 2D time series data (time is first second, second is variable number),
|
||||
* only one particular column of which is embedded
|
||||
* @param column the column index to embed
|
||||
* @param k embedding length (i.e. number of time extractions for each vector)
|
||||
* @param tau embedding delay between each point in the original time series
|
||||
* selected into each embedding vector
|
||||
* @param startKthPoint last time point of the first embedding vector
|
||||
* (i.e. use k-1 if you want to go from the start)
|
||||
* @param numEmbeddingVectors the number of embedding vectors to return
|
||||
* (i.e. use data.length-k+1 if you go from the start and want all
|
||||
* of them extracted)
|
||||
* @return a 2D array of numEmbeddingVectors embedding vectors, which are each of length k.
|
||||
*/
|
||||
public static double[][] makeDelayEmbeddingVector(double[][] data, int column, int k, int tau,
|
||||
int startKthPoint, int numEmbeddingVectors) throws Exception {
|
||||
if (startKthPoint < (k - 1)*tau) {
|
||||
throw new Exception("Start point t=" + startKthPoint + " is too early for a " +
|
||||
k + " length embedding vector with delay " + tau);
|
||||
}
|
||||
return sub;
|
||||
if (numEmbeddingVectors + startKthPoint > data.length) {
|
||||
throw new Exception("Too many embedding vectors " + numEmbeddingVectors +
|
||||
" requested for the given startPoint " + startKthPoint +
|
||||
" and time series length " + data.length);
|
||||
}
|
||||
double[][] embeddingVectors = new double[numEmbeddingVectors][k];
|
||||
for (int t = startKthPoint; t < numEmbeddingVectors + startKthPoint; t++) {
|
||||
for (int i = 0; i < k; i++) {
|
||||
embeddingVectors[t - startKthPoint][i] = data[t - i*tau][column];
|
||||
}
|
||||
}
|
||||
return embeddingVectors;
|
||||
}
|
||||
|
||||
|
||||
public static double stdDev(double[] array) {
|
||||
double mean = 0.0;
|
||||
double total = 0.0;
|
||||
|
|
|
|||
|
|
@ -62,15 +62,28 @@ public class ParsedProperties {
|
|||
/**
|
||||
* Return an integer array for a comma separated integer list,
|
||||
* or a specification of "startIndex:endIndex"
|
||||
* @param name
|
||||
* @return Integer array for the property
|
||||
*
|
||||
* @param name property name which contains the string as
|
||||
* its value.
|
||||
* @return int array for the property
|
||||
*/
|
||||
public int[] getIntArrayProperty(String name) {
|
||||
int[] returnValues;
|
||||
String repeatString = properties.getProperty(name);
|
||||
if (repeatString.indexOf(':') >= 0) {
|
||||
return parseStringArrayOfInts(repeatString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an integer array for a comma separated integer list argument,
|
||||
* or a specification of "startIndex:endIndex"
|
||||
*
|
||||
* @param stringOfInts the string contained the integers
|
||||
* @return an int array
|
||||
*/
|
||||
public static int[] parseStringArrayOfInts(String stringOfInts) {
|
||||
int[] returnValues;
|
||||
if (stringOfInts.indexOf(':') >= 0) {
|
||||
// The repeats are of the format "startIndex:endIndex"
|
||||
String[] indices = repeatString.split(":");
|
||||
String[] indices = stringOfInts.split(":");
|
||||
int startIndex = Integer.parseInt(indices[0]);
|
||||
int endIndex = Integer.parseInt(indices[1]);
|
||||
returnValues = new int[endIndex - startIndex + 1];
|
||||
|
|
@ -79,7 +92,7 @@ public class ParsedProperties {
|
|||
}
|
||||
} else {
|
||||
// The repeats are in a comma separated format
|
||||
String[] repeatStrings = repeatString.split(",");
|
||||
String[] repeatStrings = stringOfInts.split(",");
|
||||
returnValues = new int[repeatStrings.length];
|
||||
for (int i = 0; i < returnValues.length; i++) {
|
||||
returnValues[i] = Integer.parseInt(repeatStrings[i]);
|
||||
|
|
|
|||
Loading…
Reference in New Issue