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:
joseph.lizier 2014-04-17 05:58:13 +00:00
parent ac607078d5
commit 83f7de5472
20 changed files with 1639 additions and 68 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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
*

View File

@ -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>

View File

@ -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>

View File

@ -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);
}

View File

@ -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.

View File

@ -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);
}
}

View File

@ -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>

View File

@ -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;

View File

@ -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
}
}
}

View File

@ -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()}]

View File

@ -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;

View File

@ -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]);