diff --git a/java/source/infodynamics/measures/discrete/ActiveInformationCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/ActiveInformationCalculatorDiscrete.java index 7511ea25..c8d8aefa 100755 --- a/java/source/infodynamics/measures/discrete/ActiveInformationCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/ActiveInformationCalculatorDiscrete.java @@ -90,6 +90,13 @@ public static ActiveInformationCalculatorDiscrete newInstance(int base, int hist return new ActiveInformationCalculatorDiscrete(base, history); } + /** + * Construct a new instance with default base 2 and history 1 + */ + public ActiveInformationCalculatorDiscrete() { + super(); + } + /** * Construct a new instance * @@ -104,10 +111,14 @@ public ActiveInformationCalculatorDiscrete(int base, int history) { @Override public void initialise() { - super.initialise(); - aisComputed = false; + initialise(base, k); } + public void initialise(int base, int history) { + super.initialise(base, history); + aisComputed = false; + } + @Override public void addObservations(int states[]) { int timeSteps = states.length; diff --git a/java/source/infodynamics/measures/discrete/BlockEntropyCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/BlockEntropyCalculatorDiscrete.java index f7d9e28e..40bdda3d 100755 --- a/java/source/infodynamics/measures/discrete/BlockEntropyCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/BlockEntropyCalculatorDiscrete.java @@ -82,6 +82,13 @@ public static EntropyCalculatorDiscrete newInstance(int blocksize, int base) { return new BlockEntropyCalculatorDiscrete(blocksize, base); } + /** + * Construct an instance with default blocksize 1 and base 2 + */ + public BlockEntropyCalculatorDiscrete() { + this(1, 2); + } + /** * Construct a new instance * @@ -92,7 +99,10 @@ public static EntropyCalculatorDiscrete newInstance(int blocksize, int base) { public BlockEntropyCalculatorDiscrete(int blocksize, int base) { super(base); - + resetBlocksize(blocksize); + } + + private void resetBlocksize(int blocksize) { this.blocksize = blocksize; base_power_blocksize = MathsUtils.power(base, blocksize); @@ -102,19 +112,7 @@ public BlockEntropyCalculatorDiscrete(int blocksize, int base) { if (blocksize > Math.log(Integer.MAX_VALUE) / log_base) { throw new RuntimeException("Base and blocksize combination too large"); } - - // Create storage for counts of observations. - // We're recreating stateCount, which was created in super() - // however the super() didn't create it for blocksize > 1 - try { - stateCount = new int[MathsUtils.power(base, blocksize)]; - } catch (OutOfMemoryError e) { - // Allow any Exceptions to be thrown, but catch and wrap - // Error as a Runtimexception - throw new RuntimeException("Requested memory for the base " + - base + " and k=" + blocksize+ " is too large for the JVM at this time", e); - } - + // Create constants for tracking stateValues maxShiftedValue = new int[base]; for (int v = 0; v < base; v++) { @@ -122,10 +120,35 @@ public BlockEntropyCalculatorDiscrete(int blocksize, int base) { } } + public void initialise(int blocksize, int base) { + boolean baseOrBlocksizeChanged = (this.blocksize != blocksize) || (this.base != base); + + super.initialise(base); + if (baseOrBlocksizeChanged) { + resetBlocksize(blocksize); + } + + if (baseOrBlocksizeChanged || (stateCount == null)) { + // Create storage for counts of observations. + // We're recreating stateCount, which was created in super() + // however the super() didn't create it for blocksize > 1 + try { + stateCount = new int[MathsUtils.power(base, blocksize)]; + } catch (OutOfMemoryError e) { + // Allow any Exceptions to be thrown, but catch and wrap + // Error as a Runtimexception + throw new RuntimeException("Requested memory for the base " + + base + " and k=" + blocksize+ " is too large for the JVM at this time", e); + } + } else { + // Storage for sample counts exists and needs to be reset + MatrixUtils.fill(stateCount, 0); + } + } + @Override - public void initialise(){ - super.initialise(); - MatrixUtils.fill(stateCount, 0); + public void initialise() { + initialise(blocksize, base); } @Override diff --git a/java/source/infodynamics/measures/discrete/CombinedActiveEntRateCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/CombinedActiveEntRateCalculatorDiscrete.java index 66a02a19..56ee18d5 100755 --- a/java/source/infodynamics/measures/discrete/CombinedActiveEntRateCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/CombinedActiveEntRateCalculatorDiscrete.java @@ -72,9 +72,16 @@ public class CombinedActiveEntRateLocalResults { } public CombinedActiveEntRateCalculatorDiscrete() { - super(); + // TODO Make this inherit from InfoMeasureCalculatorDiscrete } + /** + * Initialise with the existing history and base + */ + public void initialise() { + initialise(k, base); + } + /** * Initialise calculator, preparing to take observation sets in * Should be called prior to any of the addObservations() methods. diff --git a/java/source/infodynamics/measures/discrete/ConditionalMutualInformationCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/ConditionalMutualInformationCalculatorDiscrete.java index a86bf680..0f144e07 100755 --- a/java/source/infodynamics/measures/discrete/ConditionalMutualInformationCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/ConditionalMutualInformationCalculatorDiscrete.java @@ -98,6 +98,15 @@ public static ConditionalMutualInformationCalculatorDiscrete newInstance(int bas return new ConditionalMutualInformationCalculatorDiscrete(base1, base2, condBase); } + /** + * Construct a new instance with default bases + */ + public ConditionalMutualInformationCalculatorDiscrete() { + + // Create super object, just with first base defaulting to 2 + this(2, 2, 2); + } + /** * Construct a new instance * @@ -110,39 +119,68 @@ public ConditionalMutualInformationCalculatorDiscrete(int base1, int base2, int // Create super object, just with first base super(base1); - + changeBases(base1, base2, condBase); + } + + /** + * Common code to be called when bases are changed (does not update arrays though) + * + * @param base1 + * @param base2 + * @param condBase + */ + private boolean changeBases(int base1, int base2, int condBase) { + boolean basesChanged = false; + if ((this.base1 != base1) || (this.base2 != base2) || (this.condBase != condBase)) { + basesChanged = true; + } // Store the bases this.base1 = base1; this.base2 = base2; this.condBase = condBase; - - // Create storage for extra counts of observations - try { - firstSecondCondCount = new int[base1][base2][condBase]; - firstCondCount = new int[base1][condBase]; - secondCondCount = new int[base2][condBase]; - condCount = new int[condBase]; - } catch (OutOfMemoryError e) { - // Allow any Exceptions to be thrown, but catch and wrap - // Error as an Exception - throw new RuntimeException("Requested memory for the MI bases (" + - base1 + ", " + base2 + ", " + condBase + - ") is too large for the JVM at this time", e); - } + return basesChanged; } - + @Override public void initialise(){ - super.initialise(); + initialise(base1, base2, condBase); + } + + /** + * Initialise with new bases + * + * @param base1 + * @param base2 + * @param condBase + */ + public void initialise(int base1, int base2, int condBase){ + boolean basesChanged = changeBases(base1, base2, condBase); + super.initialise(base1); condMiComputed = false; - - MatrixUtils.fill(firstSecondCondCount, 0); - MatrixUtils.fill(firstCondCount, 0); - MatrixUtils.fill(secondCondCount, 0); - MatrixUtils.fill(condCount,0); + + if (basesChanged || (firstSecondCondCount == null)) { + // Create storage for extra counts of observations + try { + firstSecondCondCount = new int[base1][base2][condBase]; + firstCondCount = new int[base1][condBase]; + secondCondCount = new int[base2][condBase]; + condCount = new int[condBase]; + } catch (OutOfMemoryError e) { + // Allow any Exceptions to be thrown, but catch and wrap + // Error as an Exception + throw new RuntimeException("Requested memory for the MI bases (" + + base1 + ", " + base2 + ", " + condBase + + ") is too large for the JVM at this time", e); + } + } else { + MatrixUtils.fill(firstSecondCondCount, 0); + MatrixUtils.fill(firstCondCount, 0); + MatrixUtils.fill(secondCondCount, 0); + MatrixUtils.fill(condCount,0); + } } - + /** * Add observations for the given var1,var2,cond tuples * of the variables diff --git a/java/source/infodynamics/measures/discrete/ConditionalTransferEntropyCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/ConditionalTransferEntropyCalculatorDiscrete.java index fbdc12fb..e593b7aa 100644 --- a/java/source/infodynamics/measures/discrete/ConditionalTransferEntropyCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/ConditionalTransferEntropyCalculatorDiscrete.java @@ -77,12 +77,6 @@ * be incorrect. *
* - *Note for developers: Ideally, this class would extend ContextOfPastMeasure, however - * by conditioning on other info contributors, we need to alter - * the arrays pastCount and nextPastCount to consider all - * conditioned variables (i.e. other sources) also. - *
- * * TODO Add methods for passing in single time series. * This is done for addObservations, but not other routines. * @@ -111,19 +105,17 @@ * */ public class ConditionalTransferEntropyCalculatorDiscrete - extends InfoMeasureCalculatorDiscrete + extends ContextOfPastMeasureCalculatorDiscrete implements EmpiricalNullDistributionComputer { - protected int k = 0; // history length k. protected int base_others = 0; // base of the conditional variables - protected int base_power_k = 0; protected int base_power_num_others = 0; protected int numOtherInfoContributors = 0; + protected int[][][][] sourceDestPastOthersCount = null; // count for (i-j[n],i[n+1],i[n]^k,others) tuples protected int[][][] sourcePastOthersCount = null; // count for (i-j[n],i[n]^k,others) tuples protected int[][][] destPastOthersCount = null; // Count for (i[n+1], i[n]^k,others) tuples protected int[][] pastOthersCount = null; // Count for (i[n]^k,others) - protected int[] maxShiftedValue = null; // states * (base^(k-1)) /** * First time step at which we can take an observation @@ -159,6 +151,13 @@ public class ConditionalTransferEntropyCalculatorDiscrete */ } + /** + * Construct with default parameters of base 2, history 1 and 1 other contributor + */ + public ConditionalTransferEntropyCalculatorDiscrete() { + this(2, 1, 1, 2); + } + /** * Construct a new instance. This constructor allows the source and * destination variables to have a different base from the other contributors @@ -177,53 +176,8 @@ public class ConditionalTransferEntropyCalculatorDiscrete public ConditionalTransferEntropyCalculatorDiscrete (int base, int history, int numOtherInfoContributors, int base_others) { - super(base); - - k = history; - this.base_others = base_others; - this.numOtherInfoContributors = numOtherInfoContributors; - base_power_k = MathsUtils.power(base, k); - base_power_num_others = MathsUtils.power(base_others, numOtherInfoContributors); - - // Relaxing this assumption so we can use this calculation as - // a time-lagged conditional MI at will: - //if (k < 1) { - // throw new RuntimeException("History k " + history + " is not >= 1 a ContextOfPastMeasureCalculator"); - //} - - // Which time step do we start taking observations from? - // Normally this is k (to allow k previous time steps) - // but if k==0 (becoming a lagged MI), it's 1. - startObservationTime = Math.max(k, 1); - - // check that we can convert the base tuple into an integer ok - if (k > Math.log(Integer.MAX_VALUE) / log_base) { - throw new RuntimeException("Base and history combination too large"); - } - if (numOtherInfoContributors < 1) { - throw new RuntimeException("Number of other info contributors < 1 for CompleteTECalculator"); - } - - // Create storage for counts of observations - try { - sourceDestPastOthersCount = new int[base][base][base_power_k][base_power_num_others]; - sourcePastOthersCount = new int[base][base_power_k][base_power_num_others]; - destPastOthersCount = new int [base][base_power_k][base_power_num_others]; - pastOthersCount = new int[base_power_k][base_power_num_others]; - } catch (OutOfMemoryError e) { - // Allow any Exceptions to be thrown, but catch and wrap - // Error as a RuntimeException - throw new RuntimeException("Requested memory for the base " + - base + ", k=" + k + " num of others " + numOtherInfoContributors + - " with base " + base_others + ") is too large for the JVM at this time", e); - } - - // Create constants for tracking prevValues - maxShiftedValue = new int[base]; - for (int v = 0; v < base; v++) { - maxShiftedValue[v] = v * MathsUtils.power(base, k-1); - } - + super(base, history, true); + updateParameters(base, history, numOtherInfoContributors, base_others); } /** @@ -243,14 +197,78 @@ public class ConditionalTransferEntropyCalculatorDiscrete this(base, history, numOtherInfoContributors, base); } + /** + * Private method to update the parameters, + * save for parts only concerning base and history + * which are to be handled before this by the super + * + * @param base + * @param history + * @param numOtherInfoContributors + * @param base_others + */ + private void updateParameters(int base, int history, + int numOtherInfoContributors, int base_others) { + + this.base_others = base_others; + this.numOtherInfoContributors = numOtherInfoContributors; + base_power_num_others = MathsUtils.power(base_others, numOtherInfoContributors); + + // Which time step do we start taking observations from? + // Normally this is k (to allow k previous time steps) + // but if k==0 (becoming a lagged MI), it's 1. + startObservationTime = Math.max(k, 1); + + if (numOtherInfoContributors < 1) { + throw new RuntimeException("Number of other info contributors < 1 for CompleteTECalculator"); + } + + } + + /** + * Initialise with (potentially) new parameters + * + * @param base + * @param history + * @param numOtherInfoContributors + * @param base_others + */ + public void initialise(int base, int history, + int numOtherInfoContributors, int base_others) { + + boolean paramsChanged = (this.base != base) || (k != history) || + (this.numOtherInfoContributors != numOtherInfoContributors) || + (this.base_others != base_others); + super.initialise(base, history); + if (paramsChanged) { + updateParameters(base, history, numOtherInfoContributors, base_others); + } + + if (paramsChanged || (sourceDestPastOthersCount == null)) { + // Create new storage for counts of observations + try { + sourceDestPastOthersCount = new int[base][base][base_power_k][base_power_num_others]; + sourcePastOthersCount = new int[base][base_power_k][base_power_num_others]; + destPastOthersCount = new int [base][base_power_k][base_power_num_others]; + pastOthersCount = new int[base_power_k][base_power_num_others]; + } catch (OutOfMemoryError e) { + // Allow any Exceptions to be thrown, but catch and wrap + // Error as a RuntimeException + throw new RuntimeException("Requested memory for the base " + + base + ", k=" + k + " num of others " + numOtherInfoContributors + + " with base " + base_others + ") is too large for the JVM at this time", e); + } + } else { + MatrixUtils.fill(sourceDestPastOthersCount, 0); + MatrixUtils.fill(sourcePastOthersCount, 0); + MatrixUtils.fill(destPastOthersCount, 0); + MatrixUtils.fill(pastOthersCount, 0); + } + } + @Override public void initialise(){ - super.initialise(); - - MatrixUtils.fill(sourceDestPastOthersCount, 0); - MatrixUtils.fill(sourcePastOthersCount, 0); - MatrixUtils.fill(destPastOthersCount, 0); - MatrixUtils.fill(pastOthersCount, 0); + initialise(base, k, numOtherInfoContributors, base_others); } /** diff --git a/java/source/infodynamics/measures/discrete/ContextOfPastMeasureCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/ContextOfPastMeasureCalculatorDiscrete.java index cad6374e..2ec38e35 100755 --- a/java/source/infodynamics/measures/discrete/ContextOfPastMeasureCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/ContextOfPastMeasureCalculatorDiscrete.java @@ -65,6 +65,14 @@ public abstract class ContextOfPastMeasureCalculatorDiscrete extends */ protected int base_power_k = 0; + /** + * Construct an instance with default base 2 and history 1 + * and not keeping sample counts + */ + public ContextOfPastMeasureCalculatorDiscrete() { + this(2, 1, false); + } + /** * Construct an instance * @@ -90,7 +98,18 @@ public ContextOfPastMeasureCalculatorDiscrete(int base, int history) { */ protected ContextOfPastMeasureCalculatorDiscrete(int base, int history, boolean dontCreateObsStorage) { super(base); + resetHistory(history); + + noObservationStorage = dontCreateObsStorage; + } + /** + * Should be called after {@link #resetBase(int)} has just been called. + * + * @param history + */ + private void resetHistory(int history) { + k = history; base_power_k = MathsUtils.power(base, k); @@ -108,31 +127,51 @@ protected ContextOfPastMeasureCalculatorDiscrete(int base, int history, boolean for (int v = 0; v < base; v++) { maxShiftedValue[v] = v * MathsUtils.power(base, k-1); } - - noObservationStorage = dontCreateObsStorage; - if (!dontCreateObsStorage) { - // Create storage for counts of observations - try { - nextPastCount = new int[base][base_power_k]; - pastCount = new int[base_power_k]; - nextCount = new int[base]; - } catch (OutOfMemoryError e) { - // Allow any Exceptions to be thrown, but catch and wrap - // Error as a RuntimeException - throw new RuntimeException("Requested memory for the base " + - base + " and k=" + k + " is too large for the JVM at this time", e); - } - } } @Override public void initialise() { - super.initialise(); + initialise(base, k); + } + + /** + * Initialise the calculator with (potentially new) + * specified base and history + * + * @param base + * @param history + */ + public void initialise(int base, int history) { + boolean baseOrHistoryChanged = false; + if ((this.base != base) || (k != history)) { + baseOrHistoryChanged = true; + } + + super.initialise(base); + if (baseOrHistoryChanged) { + resetHistory(history); + } if (!noObservationStorage) { - MatrixUtils.fill(nextPastCount, 0); - MatrixUtils.fill(pastCount, 0); - MatrixUtils.fill(nextCount, 0); + // We manage storage for relevant sample counts here: + if (baseOrHistoryChanged || (nextPastCount == null)) { + // Create new storage for counts of observations + try { + nextPastCount = new int[base][base_power_k]; + pastCount = new int[base_power_k]; + nextCount = new int[base]; + } catch (OutOfMemoryError e) { + // Allow any Exceptions to be thrown, but catch and wrap + // Error as a RuntimeException + throw new RuntimeException("Requested memory for the base " + + base + " and k=" + k + " is too large for the JVM at this time", e); + } + } else { + // Storage for sample counts exists and needs to be reset + MatrixUtils.fill(nextPastCount, 0); + MatrixUtils.fill(pastCount, 0); + MatrixUtils.fill(nextCount, 0); + } } } diff --git a/java/source/infodynamics/measures/discrete/EntropyCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/EntropyCalculatorDiscrete.java index d650080b..1577ffde 100755 --- a/java/source/infodynamics/measures/discrete/EntropyCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/EntropyCalculatorDiscrete.java @@ -83,6 +83,13 @@ public static EntropyCalculatorDiscrete newInstance(int base) { return new EntropyCalculatorDiscrete(base); } + /** + * Construct a new instance with default base of 2 + */ + public EntropyCalculatorDiscrete() { + this(2); + } + /** * Contruct a new instance * @@ -90,25 +97,36 @@ public static EntropyCalculatorDiscrete newInstance(int base) { * E.g. binary variables are in base-2. */ public EntropyCalculatorDiscrete(int base) { - super(base); + } + + /** + * Initialise with new base + * + * @param base + */ + public void initialise(int base){ + boolean baseChanged = (this.base != base); + super.initialise(base); - // Create storage for counts of observations - try { - stateCount = new int[base]; - } catch (OutOfMemoryError e) { - // Allow any Exceptions to be thrown, but catch and wrap - // Error as a RuntimeException - throw new RuntimeException("Requested memory for the base (" + - base + ") is too large for the JVM at this time", e); + if (baseChanged || (stateCount == null)) { + // Create storage for counts of observations + try { + stateCount = new int[base]; + } catch (OutOfMemoryError e) { + // Allow any Exceptions to be thrown, but catch and wrap + // Error as a RuntimeException + throw new RuntimeException("Requested memory for the base (" + + base + ") is too large for the JVM at this time", e); + } + } else { + MatrixUtils.fill(stateCount, 0); } - } - + @Override public void initialise(){ - super.initialise(); - MatrixUtils.fill(stateCount, 0); + initialise(base); } @Override diff --git a/java/source/infodynamics/measures/discrete/EntropyRateCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/EntropyRateCalculatorDiscrete.java index 4fd84e2e..9080c30a 100755 --- a/java/source/infodynamics/measures/discrete/EntropyRateCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/EntropyRateCalculatorDiscrete.java @@ -77,6 +77,13 @@ public static EntropyRateCalculatorDiscrete newInstance(int base, int history) { return new EntropyRateCalculatorDiscrete(base, history); } + /** + * Construct a new instance with default base 2 and history 1 + */ + public EntropyRateCalculatorDiscrete() { + super(); + } + /** * Construct a new instance * diff --git a/java/source/infodynamics/measures/discrete/InfoMeasureCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/InfoMeasureCalculatorDiscrete.java index 2825b39b..2a0ecf42 100755 --- a/java/source/infodynamics/measures/discrete/InfoMeasureCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/InfoMeasureCalculatorDiscrete.java @@ -97,6 +97,13 @@ public abstract class InfoMeasureCalculatorDiscrete { */ protected boolean debug = false; + /** + * Construct an instance with default base of 2 + */ + protected InfoMeasureCalculatorDiscrete() { + this(2); + } + /** * Construct an instance * @@ -104,7 +111,10 @@ public abstract class InfoMeasureCalculatorDiscrete { * E.g. binary variables are in base-2. */ protected InfoMeasureCalculatorDiscrete(int base) { - + resetBase(base); + } + + protected void resetBase(int base) { this.base = base; log_base = Math.log(base); @@ -122,15 +132,26 @@ protected InfoMeasureCalculatorDiscrete(int base) { /** * Initialise the calculator for re-use with new observations. * (Child classes should clear the existing PDFs) + * @throws Exception */ - public void initialise(){ + public void initialise() { + initialise(base); + } + + /** + * Initialise the calculator for re-use with new observations, + * and a new base. + * (Child classes should clear the existing PDFs) + */ + public void initialise(int base){ + resetBase(base); average = 0.0; max = 0.0; min = 0.0; std = 0.0; observations = 0; } - + /** * Return the measure last calculated in a call to * {@link #computeAverageLocalOfObservations()} diff --git a/java/source/infodynamics/measures/discrete/MultiInformationCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/MultiInformationCalculatorDiscrete.java index fe53bcbd..56fadac3 100755 --- a/java/source/infodynamics/measures/discrete/MultiInformationCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/MultiInformationCalculatorDiscrete.java @@ -68,6 +68,13 @@ public class MultiInformationCalculatorDiscrete extends InfoMeasureCalculatorDis private int jointStates; private boolean checkedFirst = false; + /** + * Construct new instance with default base 2 and numVars 2 + */ + public MultiInformationCalculatorDiscrete() { + this(2, 2); + } + /** * Construct an instance * @@ -78,25 +85,55 @@ public class MultiInformationCalculatorDiscrete extends InfoMeasureCalculatorDis */ public MultiInformationCalculatorDiscrete(int base, int numVars) { super(base); + changeParams(base, numVars); + } + + /** + * Update the parameters using numVars + * + * @param base + * @param numVars + * @return + */ + private boolean changeParams(int base, int numVars) { + boolean paramsChanged = (this.base != base) || (this.numVars != numVars); + this.numVars = numVars; jointStates = MathsUtils.power(base, numVars); - try { - jointCount = new int[jointStates]; - marginalCounts = new int[numVars][base]; - } catch (OutOfMemoryError e) { - // Allow any Exceptions to be thrown, but catch and wrap - // Error as a RuntimeException - throw new RuntimeException("Requested memory for the base " + - base + " with " + numVars + - " variables is too large for the JVM at this time", e); - } + return paramsChanged; } + + /** + * Initialise (possible) updating the base and number of variables + * + * @param base + * @param numVars + */ + public void initialise(int base, int numVars) { + boolean paramsChanged = changeParams(base, numVars); + super.initialise(base); + if(paramsChanged || (jointCount == null)) { + // Create storage for counts of observations + try { + jointCount = new int[jointStates]; + marginalCounts = new int[numVars][base]; + } catch (OutOfMemoryError e) { + // Allow any Exceptions to be thrown, but catch and wrap + // Error as a RuntimeException + throw new RuntimeException("Requested memory for the base " + + base + " with " + numVars + + " variables is too large for the JVM at this time", e); + } + } else { + MatrixUtils.fill(jointCount, 0); + MatrixUtils.fill(marginalCounts, 0); + } + } + @Override public void initialise(){ - super.initialise(); - MatrixUtils.fill(jointCount, 0); - MatrixUtils.fill(marginalCounts, 0); + initialise(base, numVars); } /** diff --git a/java/source/infodynamics/measures/discrete/MutualInformationCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/MutualInformationCalculatorDiscrete.java index 0a20ccfe..7cb0c4e7 100755 --- a/java/source/infodynamics/measures/discrete/MutualInformationCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/MutualInformationCalculatorDiscrete.java @@ -79,6 +79,16 @@ public class MutualInformationCalculatorDiscrete extends InfoMeasureCalculatorDi protected boolean miComputed = false; + /** + * Construct a new MI calculator with default bases of 2 and time difference of 0 + * between the variables + * + * @throws Exception + */ + public MutualInformationCalculatorDiscrete() throws Exception { + this(2); + } + /** * Construct a new MI calculator with default time difference of 0 * between the variables @@ -109,35 +119,78 @@ public MutualInformationCalculatorDiscrete(int base1, int base2, int timeDiff) t // Create super object, just with first base super(base1); + changeBases(base1, base2, timeDiff); + } + + /** + * Common code to be called when bases are changed (does not update arrays though) + * + * @param base1 + * @param base2 + * @param timeDiff + * @throws Exception + */ + private boolean changeBases(int base1, int base2, int timeDiff) throws Exception { + boolean basesChanged = false; + if ((this.base1 != base1) || (this.base2 != base2)) { + basesChanged = true; + } + // Store the bases this.base1 = base1; this.base2 = base2; - + if (timeDiff < 0) { throw new Exception("timeDiff must be >= 0"); } this.timeDiff = timeDiff; + + return basesChanged; + } + + @Override + public void initialise() { try { - jointCount = new int[base1][base2]; - iCount = new int[base1]; - jCount = new int[base2]; - } catch (OutOfMemoryError e) { - // Allow any Exceptions to be thrown, but catch and wrap - // Error as a RuntimeException - throw new RuntimeException("Requested memory for the MI bases (" + - base1 + ", " + base2 + ") is too large for the JVM at this time", e); + initialise(base1, base2, timeDiff); + } catch (Exception e) { + // The only possible (non runtime) exception here is that the timeDiff was < 0 + // which we've already checked, so we can cast this as a Runtime Exception + throw new RuntimeException(e); } } - @Override - public void initialise(){ - super.initialise(); - miComputed = false; - MatrixUtils.fill(iCount, 0); - MatrixUtils.fill(jCount, 0); - MatrixUtils.fill(jointCount, 0); + /** + * Initialise with new bases and time diff + * + * @param base1 + * @param base2 + * @param timeDiff + * @throws Exception + */ + public void initialise(int base1, int base2, int timeDiff) throws Exception { + boolean basesChanged = changeBases(base1, base2, timeDiff); + super.initialise(base1); + + if (basesChanged || (jointCount == null)) { + try { + jointCount = new int[base1][base2]; + iCount = new int[base1]; + jCount = new int[base2]; + } catch (OutOfMemoryError e) { + // Allow any Exceptions to be thrown, but catch and wrap + // Error as a RuntimeException + throw new RuntimeException("Requested memory for the MI bases (" + + base1 + ", " + base2 + ") is too large for the JVM at this time", e); + } + } else { + MatrixUtils.fill(iCount, 0); + MatrixUtils.fill(jCount, 0); + MatrixUtils.fill(jointCount, 0); + } + miComputed = false; + } - + /** * {@inheritDoc} * diff --git a/java/source/infodynamics/measures/discrete/PredictiveInformationCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/PredictiveInformationCalculatorDiscrete.java index fc55bc2c..1d46f7f5 100755 --- a/java/source/infodynamics/measures/discrete/PredictiveInformationCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/PredictiveInformationCalculatorDiscrete.java @@ -18,7 +18,6 @@ package infodynamics.measures.discrete; -import infodynamics.utils.MathsUtils; import infodynamics.utils.MatrixUtils; /** @@ -63,8 +62,7 @@ * * * - *TODO Inherit from {@link SingleAgentMeasureDiscreteInContextOfPastCalculator} - * as {@link ActiveInformationCalculatorDiscrete} does; Tidy up the Javadocs for + *
TODO Tidy up the Javadocs for * the methods, which are somewhat preliminary
* *References:
@@ -82,22 +80,8 @@
* @author Joseph Lizier (email,
* www)
*/
-public class PredictiveInformationCalculatorDiscrete {
+public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscreteInContextOfPastCalculator {
- private double average = 0.0;
- private double max = 0.0;
- private double min = 0.0;
- private int observations = 0;
- private int k = 0; // history/future block length k.
- private int numDiscreteValues = 0; // number of individual states.
- private int[][] jointCount = null; // Count for (x[t+1], x[t]) tuples
- private int[] prevCount = null; // Count for x[t]
- private int[] nextCount = null; // Count for x[t+1]
- private int[] maxShiftedValue = null; // states * (base^(history-1))
-
- private int base_power_k = 0;
- private double log_base = 0;
-
/**
* User was formerly forced to create new instances through this factory method.
* Retained for backwards compatibility.
@@ -111,6 +95,13 @@ public static PredictiveInformationCalculatorDiscrete newInstance(int numDiscret
return new PredictiveInformationCalculatorDiscrete(numDiscreteValues, blockLength);
}
+ /**
+ * Construct a new instance with default base 2 and history 1
+ */
+ public PredictiveInformationCalculatorDiscrete() {
+ this(2, 1);
+ }
+
/**
* Construct a new instance
*
@@ -120,55 +111,38 @@ public static PredictiveInformationCalculatorDiscrete newInstance(int numDiscret
* this is k in Schreiber's notation.
*/
public PredictiveInformationCalculatorDiscrete(int numDiscreteValues, int blockLength) {
- super();
-
- this.numDiscreteValues = numDiscreteValues;
- k = blockLength;
- base_power_k = MathsUtils.power(numDiscreteValues, k);
- log_base = Math.log(numDiscreteValues);
-
- if (blockLength < 1) {
- throw new RuntimeException("History k " + blockLength + " is not >= 1 for Predictive information calculator");
- }
- if (k > Math.log(Integer.MAX_VALUE) / log_base) {
- throw new RuntimeException("Base and history combination too large");
- }
-
- // Create storage for counts of observations
- try {
- jointCount = new int[base_power_k][base_power_k];
- prevCount = new int[base_power_k];
- nextCount = new int[base_power_k];
- } catch (OutOfMemoryError e) {
- // Allow any Exceptions to be thrown, but catch and wrap
- // Error as a RuntimeException
- throw new RuntimeException("Requested memory for the base " +
- numDiscreteValues + " with k=" + blockLength +
- ") is too large for the JVM at this time", e);
- }
-
- // Create constants for tracking prevValues and nextValues
- maxShiftedValue = new int[numDiscreteValues];
- for (int v = 0; v < numDiscreteValues; v++) {
- maxShiftedValue[v] = v * MathsUtils.power(numDiscreteValues, k-1);
+ super(numDiscreteValues, blockLength, true);
+ }
+
+ @Override
+ public void initialise(int base, int blockLength) {
+ boolean baseOrHistoryChanged = (this.base != base) || (k != blockLength);
+ super.initialise(base, blockLength);
+
+ if (baseOrHistoryChanged || (nextPastCount == null)) {
+ // Create new storage for counts of observations.
+ // Need to manage this here since next is now a block variable rather than univariate in the super.
+ try {
+ nextPastCount = new int[base_power_k][base_power_k];
+ pastCount = new int[base_power_k];
+ nextCount = new int[base_power_k];
+ } catch (OutOfMemoryError e) {
+ // Allow any Exceptions to be thrown, but catch and wrap
+ // Error as a RuntimeException
+ throw new RuntimeException("Requested memory for the base " +
+ base + " with k=" + blockLength +
+ ") is too large for the JVM at this time", e);
+ }
+ } else {
+ MatrixUtils.fill(nextPastCount, 0);
+ MatrixUtils.fill(pastCount, 0);
+ MatrixUtils.fill(nextCount, 0);
}
}
-
- /**
- * Initialise calculator, preparing to take observation sets in
- * Should be called prior to any of the addObservations() methods.
- * You can reinitialise without needing to create a new object.
- *
- */
+
+ @Override
public void initialise(){
- average = 0.0;
- max = 0.0;
- min = 0.0;
- observations = 0;
-
- MatrixUtils.fill(jointCount, 0);
- MatrixUtils.fill(prevCount, 0);
- MatrixUtils.fill(nextCount, 0);
+ initialise(base, k);
}
/**
@@ -191,9 +165,9 @@ public void addObservations(int timeSeries[]) {
int prevVal = 0;
int nextVal = 0;
for (int p = 0; p < k; p++) {
- prevVal *= numDiscreteValues;
+ prevVal *= base;
prevVal += timeSeries[p];
- nextVal *= numDiscreteValues;
+ nextVal *= base;
nextVal += timeSeries[k-1+p];
}
@@ -201,15 +175,15 @@ public void addObservations(int timeSeries[]) {
for (int t = k; t < timeSteps - (k-1); t++) {
// Update the next value:
nextVal -= maxShiftedValue[timeSeries[t-1]];
- nextVal *= numDiscreteValues;
+ nextVal *= base;
nextVal += timeSeries[k-1+t];
// Update the counts
- jointCount[nextVal][prevVal]++;
- prevCount[prevVal]++;
+ nextPastCount[nextVal][prevVal]++;
+ pastCount[prevVal]++;
nextCount[nextVal]++;
// Update the previous value:
prevVal -= maxShiftedValue[timeSeries[t-k]];
- prevVal *= numDiscreteValues;
+ prevVal *= base;
prevVal += timeSeries[t];
}
}
@@ -239,9 +213,9 @@ public void addObservations(int states[][]) {
prevVal[c] = 0;
nextVal[c] = 0;
for (int p = 0; p < k; p++) {
- prevVal[c] *= numDiscreteValues;
+ prevVal[c] *= base;
prevVal[c] += states[p][c];
- nextVal[c] *= numDiscreteValues;
+ nextVal[c] *= base;
nextVal[c] += states[k-1+p][c];
}
}
@@ -251,15 +225,15 @@ public void addObservations(int states[][]) {
for (int c = 0; c < columns; c++) {
// Update the next value:
nextVal[c] -= maxShiftedValue[states[r-1][c]];
- nextVal[c] *= numDiscreteValues;
+ nextVal[c] *= base;
nextVal[c] += states[k-1+r][c];
// Update the counts
- jointCount[nextVal[c]][prevVal[c]]++;
- prevCount[prevVal[c]]++;
+ nextPastCount[nextVal[c]][prevVal[c]]++;
+ pastCount[prevVal[c]]++;
nextCount[nextVal[c]]++;
// Update the previous value:
prevVal[c] -= maxShiftedValue[states[r-k][c]];
- prevVal[c] *= numDiscreteValues;
+ prevVal[c] *= base;
prevVal[c] += states[r][c];
}
}
@@ -296,9 +270,9 @@ public void addObservations(int states[][][]) {
prevVal[r][c] = 0;
nextVal[r][c] = 0;
for (int p = 0; p < k; p++) {
- prevVal[r][c] *= numDiscreteValues;
+ prevVal[r][c] *= base;
prevVal[r][c] += states[p][r][c];
- nextVal[r][c] *= numDiscreteValues;
+ nextVal[r][c] *= base;
nextVal[r][c] += states[k-1+p][r][c];
}
}
@@ -310,15 +284,15 @@ public void addObservations(int states[][][]) {
for (int c = 0; c < agentColumns; c++) {
// Update the next value:
nextVal[r][c] -= maxShiftedValue[states[t-1][r][c]];
- nextVal[r][c] *= numDiscreteValues;
+ nextVal[r][c] *= base;
nextVal[r][c] += states[k-1+t][r][c];
// Update the counts
- jointCount[nextVal[r][c]][prevVal[r][c]]++;
- prevCount[prevVal[r][c]]++;
+ nextPastCount[nextVal[r][c]][prevVal[r][c]]++;
+ pastCount[prevVal[r][c]]++;
nextCount[nextVal[r][c]]++;
// Update the previous value:
prevVal[r][c] -= maxShiftedValue[states[t-k][r][c]];
- prevVal[r][c] *= numDiscreteValues;
+ prevVal[r][c] *= base;
prevVal[r][c] += states[t][r][c];
}
}
@@ -347,9 +321,9 @@ public void addObservations(int states[][], int col) {
int prevVal = 0;
int nextVal = 0;
for (int p = 0; p < k; p++) {
- prevVal *= numDiscreteValues;
+ prevVal *= base;
prevVal += states[p][col];
- nextVal *= numDiscreteValues;
+ nextVal *= base;
nextVal += states[k-1+p][col];
}
@@ -357,16 +331,16 @@ public void addObservations(int states[][], int col) {
for (int r = k; r < rows - (k-1); r++) {
// Update the next value:
nextVal -= maxShiftedValue[states[r-1][col]];
- nextVal *= numDiscreteValues;
+ nextVal *= base;
nextVal += states[k-1+r][col];
// Add to the count for this particular transition:
// (cell's assigned as above)
- jointCount[nextVal][prevVal]++;
- prevCount[prevVal]++;
+ nextPastCount[nextVal][prevVal]++;
+ pastCount[prevVal]++;
nextCount[nextVal]++;
// Update the previous value:
prevVal -= maxShiftedValue[states[r-k][col]];
- prevVal *= numDiscreteValues;
+ prevVal *= base;
prevVal += states[r][col];
}
}
@@ -394,9 +368,9 @@ public void addObservations(int states[][][], int agentIndex1, int agentIndex2)
int prevVal = 0;
int nextVal = 0;
for (int p = 0; p < k; p++) {
- prevVal *= numDiscreteValues;
+ prevVal *= base;
prevVal += states[p][agentIndex1][agentIndex2];
- nextVal *= numDiscreteValues;
+ nextVal *= base;
nextVal += states[k-1+p][agentIndex1][agentIndex2];
}
@@ -404,26 +378,21 @@ public void addObservations(int states[][][], int agentIndex1, int agentIndex2)
for (int t = k; t < timeSteps - (k-1); t++) {
// Update the next value:
nextVal -= maxShiftedValue[states[t-1][agentIndex1][agentIndex2]];
- nextVal *= numDiscreteValues;
+ nextVal *= base;
nextVal += states[k-1+t][agentIndex1][agentIndex2];
// Add to the count for this particular transition:
// (cell's assigned as above)
- jointCount[nextVal][prevVal]++;
- prevCount[prevVal]++;
+ nextPastCount[nextVal][prevVal]++;
+ pastCount[prevVal]++;
nextCount[nextVal]++;
// Update the previous value:
prevVal -= maxShiftedValue[states[t-k][agentIndex1][agentIndex2]];
- prevVal *= numDiscreteValues;
+ prevVal *= base;
prevVal += states[t][agentIndex1][agentIndex2];
}
}
- /**
- * Returns the average predictive information from
- * the observed values which have been passed in previously.
- *
- * @return
- */
+ @Override
public double computeAverageLocalOfObservations() {
double mi = 0.0;
double miCont = 0.0;
@@ -435,9 +404,9 @@ public double computeAverageLocalOfObservations() {
double p_next = (double) nextCount[nextVal] / (double) observations;
for (int prevVal = 0; prevVal < base_power_k; prevVal++) {
// compute p_prev
- double p_prev = (double) prevCount[prevVal] / (double) observations;
+ double p_prev = (double) pastCount[prevVal] / (double) observations;
// compute p(prev, next)
- double p_joint = (double) jointCount[nextVal][prevVal] / (double) observations;
+ double p_joint = (double) nextPastCount[nextVal][prevVal] / (double) observations;
// Compute MI contribution:
if (p_joint > 0.0) {
double logTerm = p_joint / (p_next * p_prev);
@@ -469,9 +438,9 @@ public double computeAverageLocalOfObservations() {
* @return
*/
public double computeLocalFromPreviousObservations(int next, int past){
- double logTerm = ( (double) jointCount[next][past] ) /
+ double logTerm = ( (double) nextPastCount[next][past] ) /
( (double) nextCount[next] *
- (double) prevCount[past] );
+ (double) pastCount[past] );
logTerm *= (double) observations;
return Math.log(logTerm) / log_base;
}
@@ -503,9 +472,9 @@ public double[] computeLocalFromPreviousObservations(int timeSeries[]){
int prevVal = 0;
int nextVal = 0;
for (int p = 0; p < k; p++) {
- prevVal *= numDiscreteValues;
+ prevVal *= base;
prevVal += timeSeries[p];
- nextVal *= numDiscreteValues;
+ nextVal *= base;
nextVal += timeSeries[k-1+p];
}
@@ -513,11 +482,11 @@ public double[] computeLocalFromPreviousObservations(int timeSeries[]){
for (int t = k; t < timeSteps - (k-1); t++) {
// Update the next value:
nextVal -= maxShiftedValue[timeSeries[t-1]];
- nextVal *= numDiscreteValues;
+ nextVal *= base;
nextVal += timeSeries[k-1+t];
- logTerm = ( (double) jointCount[nextVal][prevVal] ) /
+ logTerm = ( (double) nextPastCount[nextVal][prevVal] ) /
( (double) nextCount[nextVal] *
- (double) prevCount[prevVal] );
+ (double) pastCount[prevVal] );
// Now account for the fact that we've
// just used counts rather than probabilities,
// and we've got two counts on the bottom
@@ -532,7 +501,7 @@ public double[] computeLocalFromPreviousObservations(int timeSeries[]){
}
// Update the previous value:
prevVal -= maxShiftedValue[timeSeries[t-k]];
- prevVal *= numDiscreteValues;
+ prevVal *= base;
prevVal += timeSeries[t];
}
average = average/(double) (timeSteps - k - (k-1));
@@ -574,9 +543,9 @@ public double[][] computeLocalFromPreviousObservations(int timeSeries[][]){
prevVal[c] = 0;
nextVal[c] = 0;
for (int p = 0; p < k; p++) {
- prevVal[c] *= numDiscreteValues;
+ prevVal[c] *= base;
prevVal[c] += timeSeries[p][c];
- nextVal[c] *= numDiscreteValues;
+ nextVal[c] *= base;
nextVal[c] += timeSeries[k-1+p][c];
}
}
@@ -585,11 +554,11 @@ public double[][] computeLocalFromPreviousObservations(int timeSeries[][]){
for (int c = 0; c < columns; c++) {
// Update the next value:
nextVal[c] -= maxShiftedValue[timeSeries[r-1][c]];
- nextVal[c] *= numDiscreteValues;
+ nextVal[c] *= base;
nextVal[c] += timeSeries[k-1+r][c];
- logTerm = ( (double) jointCount[nextVal[c]][prevVal[c]] ) /
+ logTerm = ( (double) nextPastCount[nextVal[c]][prevVal[c]] ) /
( (double) nextCount[nextVal[c]] *
- (double) prevCount[prevVal[c]] );
+ (double) pastCount[prevVal[c]] );
// Now account for the fact that we've
// just used counts rather than probabilities,
// and we've got two counts on the bottom
@@ -604,7 +573,7 @@ public double[][] computeLocalFromPreviousObservations(int timeSeries[][]){
}
// Update the previous value:
prevVal[c] -= maxShiftedValue[timeSeries[r-k][c]];
- prevVal[c] *= numDiscreteValues;
+ prevVal[c] *= base;
prevVal[c] += timeSeries[r][c];
}
}
@@ -649,9 +618,9 @@ public double[][][] computeLocalFromPreviousObservations(int timeSeries[][][]){
prevVal[r][c] = 0;
nextVal[r][c] = 0;
for (int p = 0; p < k; p++) {
- prevVal[r][c] *= numDiscreteValues;
+ prevVal[r][c] *= base;
prevVal[r][c] += timeSeries[p][r][c];
- nextVal[r][c] *= numDiscreteValues;
+ nextVal[r][c] *= base;
nextVal[r][c] += timeSeries[k-1+p][r][c];
}
}
@@ -662,11 +631,11 @@ public double[][][] computeLocalFromPreviousObservations(int timeSeries[][][]){
for (int c = 0; c < agentColumns; c++) {
// Update the next value:
nextVal[r][c] -= maxShiftedValue[timeSeries[t-1][r][c]];
- nextVal[r][c] *= numDiscreteValues;
+ nextVal[r][c] *= base;
nextVal[r][c] += timeSeries[k-1+t][r][c];
- logTerm = ( (double) jointCount[nextVal[r][c]][prevVal[r][c]] ) /
+ logTerm = ( (double) nextPastCount[nextVal[r][c]][prevVal[r][c]] ) /
( (double) nextCount[nextVal[r][c]] *
- (double) prevCount[prevVal[r][c]] );
+ (double) pastCount[prevVal[r][c]] );
// Now account for the fact that we've
// just used counts rather than probabilities,
// and we've got two counts on the bottom
@@ -681,7 +650,7 @@ public double[][][] computeLocalFromPreviousObservations(int timeSeries[][][]){
}
// Update the previous value:
prevVal[r][c] -= maxShiftedValue[timeSeries[t-k][r][c]];
- prevVal[r][c] *= numDiscreteValues;
+ prevVal[r][c] *= base;
prevVal[r][c] += timeSeries[t][r][c];
}
}
@@ -721,20 +690,20 @@ public double[] computeLocalFromPreviousObservations(int states[][], int col){
int prevVal = 0;
int nextVal = 0;
for (int p = 0; p < k; p++) {
- prevVal *= numDiscreteValues;
+ prevVal *= base;
prevVal += states[p][col];
- nextVal *= numDiscreteValues;
+ nextVal *= base;
nextVal += states[k-1+p][col];
}
double logTerm = 0.0;
for (int r = k; r < rows - (k-1); r++) {
// Update the next value:
nextVal -= maxShiftedValue[states[r-1][col]];
- nextVal *= numDiscreteValues;
+ nextVal *= base;
nextVal += states[k-1+r][col];
- logTerm = ( (double) jointCount[nextVal][prevVal] ) /
+ logTerm = ( (double) nextPastCount[nextVal][prevVal] ) /
( (double) nextCount[nextVal] *
- (double) prevCount[prevVal] );
+ (double) pastCount[prevVal] );
// Now account for the fact that we've
// just used counts rather than probabilities,
// and we've got two counts on the bottom
@@ -749,7 +718,7 @@ public double[] computeLocalFromPreviousObservations(int states[][], int col){
}
// Update the previous value:
prevVal -= maxShiftedValue[states[r-k][col]];
- prevVal *= numDiscreteValues;
+ prevVal *= base;
prevVal += states[r][col];
}
average = average/(double) (rows - k - (k-1));
@@ -789,20 +758,20 @@ public double[] computeLocalFromPreviousObservations(int timeSeries[][][], int a
int prevVal = 0;
int nextVal = 0;
for (int p = 0; p < k; p++) {
- prevVal *= numDiscreteValues;
+ prevVal *= base;
prevVal += timeSeries[p][agentIndex1][agentIndex2];
- nextVal *= numDiscreteValues;
+ nextVal *= base;
nextVal += timeSeries[k-1+p][agentIndex1][agentIndex2];
}
double logTerm = 0.0;
for (int t = k; t < timeSteps - (k-1); t++) {
// Update the next value:
nextVal -= maxShiftedValue[timeSeries[t-1][agentIndex1][agentIndex2]];
- nextVal *= numDiscreteValues;
+ nextVal *= base;
nextVal += timeSeries[k-1+t][agentIndex1][agentIndex2];
- logTerm = ( (double) jointCount[nextVal][prevVal] ) /
+ logTerm = ( (double) nextPastCount[nextVal][prevVal] ) /
( (double) nextCount[nextVal] *
- (double) prevCount[prevVal] );
+ (double) pastCount[prevVal] );
// Now account for the fact that we've
// just used counts rather than probabilities,
// and we've got two counts on the bottom
@@ -817,7 +786,7 @@ public double[] computeLocalFromPreviousObservations(int timeSeries[][][], int a
}
// Update the previous value:
prevVal -= maxShiftedValue[timeSeries[t-k][agentIndex1][agentIndex2]];
- prevVal *= numDiscreteValues;
+ prevVal *= base;
prevVal += timeSeries[t][agentIndex1][agentIndex2];
}
average = average/(double) (timeSteps - k - (k-1));
@@ -826,215 +795,6 @@ public double[] computeLocalFromPreviousObservations(int timeSeries[][][], int a
}
- /**
- * Standalone routine to
- * compute local predictive information from a time series.
- * Return an array of local values.
- * First k and last k-1 rows are zeros.
- *
- * @param timeSeries time series array of states
- * @return time series of local predictive information values
- */
- public double[] computeLocal(int timeSeries[]) {
-
- initialise();
- addObservations(timeSeries);
- return computeLocalFromPreviousObservations(timeSeries);
- }
-
- /**
- * Standalone routine to
- * compute local predictive information across a 2D spatiotemporal
- * time series of the observations of homogeneous agents.
- * This method to be called for homogeneous agents only, as all
- * observations are pooled together.
- * First k and last k-1 rows are zeros.
- *
- * @param timeSeries 2D array of states (first index is time, second is variable id)
- * @return multivariate time series of local predictive information values
- * (1st index is time, second is variable id)
- */
- public double[][] computeLocal(int timeSeries[][]) {
-
- initialise();
- addObservations(timeSeries);
- return computeLocalFromPreviousObservations(timeSeries);
- }
-
- /**
- * Standalone routine to
- * compute local predictive information across a 3D spatiotemporal
- * array of the states of homogeneous agents
- * This method to be called for homogeneous agents only, as all
- * observations are pooled together.
- * First k and last k-1 rows are zeros.
- *
- * @param timeSeries 2D array of states (first index is time, second
- * and third are variable ids)
- * @return multivariate time series of local predictive information values
- * (1st index is time, second and third are variable ids)
- */
- public double[][][] computeLocal(int timeSeries[][][]) {
-
- initialise();
- addObservations(timeSeries);
- return computeLocalFromPreviousObservations(timeSeries);
- }
-
- /**
- * Standalone routine to
- * compute average predictive information across a
- * time series.
- *
- * @param timeSeries time series array of states
- * @return average predictive information values
- */
- public double computeAverageLocal(int timeSeries[]) {
-
- initialise();
- addObservations(timeSeries);
- return computeAverageLocalOfObservations();
- }
-
- /**
- * Standalone routine to
- * compute average predictive information across a 2D spatiotemporal
- * array of the states of homogeneous agents.
- * This method to be called for homogeneous agents only, as all
- * observations are pooled together.
- *
- * @param timeSeries 2D array of states (first index is time, second is variable id)
- * @return average predictive information value
- */
- public double computeAverageLocal(int timeSeries[][]) {
-
- initialise();
- addObservations(timeSeries);
- return computeAverageLocalOfObservations();
- }
-
- /**
- * Standalone routine to
- * compute average predictive information across a 3D spatiotemporal
- * array of the states of homogeneous agents
- * This method to be called for homogeneous agents only, as all
- * observations are pooled together.
- *
- * @param timeSeries 2D array of states (first index is time, second
- * and third are variable ids)
- * @return average predictive information value
- */
- public double computeAverageLocal(int timeSeries[][][]) {
-
- initialise();
- addObservations(timeSeries);
- return computeAverageLocalOfObservations();
- }
-
- /**
- * Standalone routine to
- * compute local predictive information for one agent in a 2D spatiotemporal
- * array of the states of agents
- * First k and last k-1 rows are zeros.
- *
- * This method should be used for heterogeneous agents.
- *
- * @param timeSeries 2D array of states (first index is time, second is variable id)
- * @param col index of the agent whose local values should be calculated
- * @return time series of local predictive information values for the given agent id
- */
- public double[] computeLocal(int timeSeries[][], int col) {
-
- initialise();
- addObservations(timeSeries, col);
- return computeLocalFromPreviousObservations(timeSeries, col);
- }
-
- /**
- * Standalone routine to
- * compute local predictive information for one agent in a 3D spatiotemporal
- * array of the states of agents
- * First k and last k-1 rows are zeros.
- * This method should be used for heterogeneous agents.
- *
- * @param timeSeries 3D array of states (first index is time, second
- * and third are variable id)
- * @param agentIndex1 row index of agent
- * @param agentIndex2 column index of agent
- * @return time series of local predictive information values for the given agent id
- */
- public double[] computeLocal(int timeSeries[][][], int agentIndex1, int agentIndex2) {
-
- initialise();
- addObservations(timeSeries, agentIndex1, agentIndex2);
- return computeLocalFromPreviousObservations(timeSeries, agentIndex1, agentIndex2);
- }
-
- /**
- * Standalone routine to
- * compute average local predictive information
- * for a single agent in a 2D spatiotemporal time series.
- * This method suitable for heterogeneous agents, since the agent
- * to be investigated is named.
- *
- * @param timeSeries 2D array of states (first index is time, second is variable id)
- * @param col index of the agent whose local values should be calculated
- * @return average predictive info for the given agent id
- */
- public double computeAverageLocal(int timeSeries[][], int col) {
-
- initialise();
- addObservations(timeSeries, col);
- return computeAverageLocalOfObservations();
- }
-
- /**
- * Standalone routine to
- * compute average local active information storage
- * for a single agent in a 3D spatiotemporal time series.
- * This method suitable for heterogeneous agents, since the agent
- * to be investigated is named.
- *
- * @param timeSeries 3D array of states (first index is time, second
- * and third are variable id)
- * @param agentIndex1 row index of agent
- * @param agentIndex2 column index of agent
- * @return average predictive info for the given agent id
- */
- public double computeAverageLocal(int timeSeries[][][], int agentIndex1, int agentIndex2) {
-
- initialise();
- addObservations(timeSeries, agentIndex1, agentIndex2);
- return computeAverageLocalOfObservations();
- }
-
- /**
- *
- * @return the last predictive information computed since the
- * previous {@link #initialise()} call.
- */
- public double getLastAverage() {
- return average;
- }
-
- /**
- *
- * @return the last maximum local predictive information computed since the
- * previous {@link #initialise()} call.
- */
- public double getLastMax() {
- return max;
- }
-
- /**
- *
- * @return the last minimum local predictive information computed since the
- * previous {@link #initialise()} call.
- */
- public double getLastMin() {
- return min;
- }
-
/**
* Writes the current probability distribution functions
*
@@ -1050,9 +810,9 @@ public void writePdfs() {
double p_next = (double) nextCount[nextVal] / (double) observations;
for (int prevVal = 0; prevVal < base_power_k; prevVal++) {
// compute p_prev
- double p_prev = (double) prevCount[prevVal] / (double) observations;
+ double p_prev = (double) pastCount[prevVal] / (double) observations;
// compute p(prev, next)
- double p_joint = (double) jointCount[nextVal][prevVal] / (double) observations;
+ double p_joint = (double) nextPastCount[nextVal][prevVal] / (double) observations;
// Compute MI contribution:
if (p_joint > 0.0) {
double logTerm = p_joint / (p_next * p_prev);
@@ -1084,7 +844,7 @@ public void writePdfs() {
public int computePastValue(int[] x, int t) {
int pastVal = 0;
for (int p = 0; p < k; p++) {
- pastVal *= numDiscreteValues;
+ pastVal *= base;
pastVal += x[t - k + 1 + p];
}
return pastVal;
@@ -1103,7 +863,7 @@ public int computePastValue(int[] x, int t) {
public int computePastValue(int[][] x, int i, int t) {
int pastVal = 0;
for (int p = 0; p < k; p++) {
- pastVal *= numDiscreteValues;
+ pastVal *= base;
pastVal += x[t - k + 1 + p][i];
}
return pastVal;
@@ -1123,7 +883,7 @@ public int computePastValue(int[][] x, int i, int t) {
public int computePastValue(int[][][] x, int i, int j, int t) {
int pastVal = 0;
for (int p = 0; p < k; p++) {
- pastVal *= numDiscreteValues;
+ pastVal *= base;
pastVal += x[t - k + 1 + p][i][j];
}
return pastVal;
diff --git a/java/source/infodynamics/measures/discrete/SingleAgentMeasureDiscrete.java b/java/source/infodynamics/measures/discrete/SingleAgentMeasureDiscrete.java
index f02af641..896b5e4e 100755
--- a/java/source/infodynamics/measures/discrete/SingleAgentMeasureDiscrete.java
+++ b/java/source/infodynamics/measures/discrete/SingleAgentMeasureDiscrete.java
@@ -42,6 +42,13 @@
*/
public interface SingleAgentMeasureDiscrete {
+ /**
+ * Initialise the calculator with (potentially) a new base
+ *
+ * @param base
+ */
+ public void initialise(int base);
+
/**
* Add observations in to our estimates of the pdfs.
*
diff --git a/java/source/infodynamics/measures/discrete/SingleAgentMeasureDiscreteInContextOfPastCalculator.java b/java/source/infodynamics/measures/discrete/SingleAgentMeasureDiscreteInContextOfPastCalculator.java
index e6051616..d9af5939 100755
--- a/java/source/infodynamics/measures/discrete/SingleAgentMeasureDiscreteInContextOfPastCalculator.java
+++ b/java/source/infodynamics/measures/discrete/SingleAgentMeasureDiscreteInContextOfPastCalculator.java
@@ -46,6 +46,13 @@
public abstract class SingleAgentMeasureDiscreteInContextOfPastCalculator extends
ContextOfPastMeasureCalculatorDiscrete implements SingleAgentMeasureDiscrete {
+ /**
+ * Construct the calculator with default base of 2 and history 1
+ */
+ public SingleAgentMeasureDiscreteInContextOfPastCalculator() {
+ super(2, 1);
+ }
+
/**
* Construct the calculator
*
@@ -57,6 +64,20 @@ public SingleAgentMeasureDiscreteInContextOfPastCalculator(int base, int history
super(base, history);
}
+ /**
+ * Construct the calculator
+ *
+ * @param base number of quantisation levels for each variable.
+ * E.g. binary variables are in base-2.
+ * @param history embedding length
+ * @param dontCreateObsStorage do not create storage
+ * for observations of the embedded past (as the child
+ * class is signalling that it does not need it)
+ */
+ public SingleAgentMeasureDiscreteInContextOfPastCalculator(int base, int history, boolean dontCreateObsStorage) {
+ super(base, history, dontCreateObsStorage);
+ }
+
@Override
public final double[] computeLocal(int[] states) {
initialise();
diff --git a/java/source/infodynamics/measures/discrete/TransferEntropyCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/TransferEntropyCalculatorDiscrete.java
index cea5a172..a178b1ac 100755
--- a/java/source/infodynamics/measures/discrete/TransferEntropyCalculatorDiscrete.java
+++ b/java/source/infodynamics/measures/discrete/TransferEntropyCalculatorDiscrete.java
@@ -173,6 +173,15 @@ public static TransferEntropyCalculatorDiscrete newInstance(int base, int destHi
*/
}
+ /**
+ * Create a new TE calculator with all parameters as default
+ * (base 2 and all embedding/delay parameters 1)
+ *
+ */
+ public TransferEntropyCalculatorDiscrete() {
+ this(2, 1, 1, 1, 1, 1);
+ }
+
/**
* Create a new TE calculator for the given base and destination history embedding length
* (leave the other embedding parameters as default)
@@ -223,6 +232,25 @@ public TransferEntropyCalculatorDiscrete(int base, int destHistoryEmbedLength, i
int sourceHistoryEmbeddingLength, int sourceEmbeddingDelay, int delay) {
super(base, destHistoryEmbedLength);
+ updateParameters(base, destHistoryEmbedLength, destEmbeddingDelay,
+ sourceHistoryEmbeddingLength, sourceEmbeddingDelay, delay);
+ }
+
+ /**
+ * Private method to update the estimators parameters,
+ * save for parts only concerning base and destHistoryEmbedLength
+ * which are to be handled before this by the super
+ *
+ * @param base
+ * @param destHistoryEmbedLength
+ * @param destEmbeddingDelay
+ * @param sourceHistoryEmbeddingLength
+ * @param sourceEmbeddingDelay
+ * @param delay
+ */
+ private void updateParameters(int base, int destHistoryEmbedLength, int destEmbeddingDelay,
+ int sourceHistoryEmbeddingLength, int sourceEmbeddingDelay, int delay) {
+
this.destEmbeddingDelay = destEmbeddingDelay;
if (sourceHistoryEmbeddingLength <= 0) {
throw new RuntimeException("Cannot have source embedding length of zero or less");
@@ -243,18 +271,6 @@ public TransferEntropyCalculatorDiscrete(int base, int destHistoryEmbedLength, i
maxShiftedSourceValue[v] = v * MathsUtils.power(base, sourceHistoryEmbedLength-1);
}
- // Create storage for extra counts of observations
- try {
- sourceNextPastCount = new int[base_power_l][base][base_power_k];
- sourcePastCount = new int[base_power_l][base_power_k];
- } catch (OutOfMemoryError e) {
- // Allow any Exceptions to be thrown, but catch and wrap
- // Error as a RuntimeException
- throw new RuntimeException("Requested memory for the base " +
- base + ", k=" + k + ", l=" + sourceHistoryEmbedLength +
- " is too large for the JVM at this time", e);
- }
-
// Which time step do we start taking observations from?
// These two integers represent the earliest next time step, in the cases where the destination
// embedding itself determines where we can start taking observations, or
@@ -263,16 +279,53 @@ public TransferEntropyCalculatorDiscrete(int base, int destHistoryEmbedLength, i
int startTimeBasedOnDestPast = (k-1)*destEmbeddingDelay + 1;
int startTimeBasedOnSourcePast = (sourceHistoryEmbedLength-1)*sourceEmbeddingDelay + delay;
startObservationTime = Math.max(startTimeBasedOnDestPast, startTimeBasedOnSourcePast);
-
}
-
+
+ /**
+ * Initialise with (potentially) new parameters
+ *
+ * @param base
+ * @param destHistoryEmbedLength
+ * @param destEmbeddingDelay
+ * @param sourceHistoryEmbeddingLength
+ * @param sourceEmbeddingDelay
+ * @param delay
+ */
+ public void initialise(int base, int destHistoryEmbedLength, int destEmbeddingDelay,
+ int sourceHistoryEmbeddingLength, int sourceEmbeddingDelay, int delay) {
+
+ boolean paramsChanged = (this.base != base) || (k != destHistoryEmbedLength) ||
+ (this.destEmbeddingDelay != destEmbeddingDelay) || (this.sourceHistoryEmbedLength != sourceHistoryEmbeddingLength) ||
+ (this.sourceEmbeddingDelay != sourceEmbeddingDelay) || (this.delay != delay);
+ super.initialise(base, destHistoryEmbedLength);
+ if (paramsChanged) {
+ updateParameters(base, destHistoryEmbedLength, destEmbeddingDelay,
+ sourceHistoryEmbeddingLength, sourceEmbeddingDelay, delay);
+ }
+
+ if (paramsChanged || (sourceNextPastCount == null)) {
+ // Create new storage for extra counts of observations
+ try {
+ sourceNextPastCount = new int[base_power_l][base][base_power_k];
+ sourcePastCount = new int[base_power_l][base_power_k];
+ } catch (OutOfMemoryError e) {
+ // Allow any Exceptions to be thrown, but catch and wrap
+ // Error as a RuntimeException
+ throw new RuntimeException("Requested memory for the base " +
+ base + ", k=" + k + ", l=" + sourceHistoryEmbedLength +
+ " is too large for the JVM at this time", e);
+ }
+ } else {
+ MatrixUtils.fill(sourceNextPastCount, 0);
+ MatrixUtils.fill(sourcePastCount, 0);
+ }
+ estimateComputed = false;
+ }
+
@Override
public void initialise(){
- super.initialise();
- estimateComputed = false;
-
- MatrixUtils.fill(sourceNextPastCount, 0);
- MatrixUtils.fill(sourcePastCount, 0);
+ initialise(base, k, destEmbeddingDelay, sourceHistoryEmbedLength,
+ sourceEmbeddingDelay, delay);
}
@Override