diff --git a/java/source/infodynamics/measures/discrete/ActiveInformationCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/ActiveInformationCalculatorDiscrete.java index c8d8aef..e565352 100755 --- a/java/source/infodynamics/measures/discrete/ActiveInformationCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/ActiveInformationCalculatorDiscrete.java @@ -72,7 +72,7 @@ import infodynamics.utils.RandomGenerator; * @author Joseph Lizier (email, * www) */ -public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscreteInContextOfPastCalculator +public class ActiveInformationCalculatorDiscrete extends UnivariateMeasureDiscreteInContextOfPastCalculator implements EmpiricalNullDistributionComputer, AnalyticNullDistributionComputer { protected boolean aisComputed = false; @@ -111,7 +111,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr @Override public void initialise() { - initialise(base, k); + initialise(alphabetSize, k); } public void initialise(int base, int history) { @@ -128,7 +128,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr // Initialise and store the current previous value for each column int prevVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[p]; } @@ -142,7 +142,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr nextCount[nextVal]++; // Update the previous value: prevVal -= maxShiftedValue[states[t-k]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[t]; } } @@ -159,7 +159,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr for (int c = 0; c < columns; c++) { prevVal[c] = 0; for (int p = 0; p < k; p++) { - prevVal[c] *= base; + prevVal[c] *= alphabetSize; prevVal[c] += states[p][c]; } } @@ -176,13 +176,12 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr nextCount[nextVal]++; // Update the previous value: prevVal[c] -= maxShiftedValue[states[r-k][c]]; - prevVal[c] *= base; + prevVal[c] *= alphabetSize; prevVal[c] += states[r][c]; } } } - @Override public void addObservations(int states[][][]) { int timeSteps = states.length; if (timeSteps == 0) { @@ -202,7 +201,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr for (int c = 0; c < agentColumns; c++) { prevVal[r][c] = 0; for (int p = 0; p < k; p++) { - prevVal[r][c] *= base; + prevVal[r][c] *= alphabetSize; prevVal[r][c] += states[p][r][c]; } } @@ -221,14 +220,13 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr nextCount[nextVal]++; // Update the previous value: prevVal[r][c] -= maxShiftedValue[states[t-k][r][c]]; - prevVal[r][c] *= base; + prevVal[r][c] *= alphabetSize; prevVal[r][c] += states[t][r][c]; } } } } - @Override public void addObservations(int states[][], int col) { int rows = states.length; // increment the count of observations: @@ -238,7 +236,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr int prevVal = 0; prevVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[p][col]; } @@ -253,12 +251,11 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr nextCount[nextVal]++; // Update the previous value: prevVal -= maxShiftedValue[states[r-k][col]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[r][col]; } } - @Override public void addObservations(int states[][][], int agentIndex1, int agentIndex2) { int timeSteps = states.length; // increment the count of observations: @@ -268,7 +265,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr int prevVal = 0; prevVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[p][agentIndex1][agentIndex2]; } @@ -283,7 +280,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr nextCount[nextVal]++; // Update the previous value: prevVal -= maxShiftedValue[states[t-k][agentIndex1][agentIndex2]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[t][agentIndex1][agentIndex2]; } } @@ -295,7 +292,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr max = 0; min = 0; - for (int nextVal = 0; nextVal < base; nextVal++) { + for (int nextVal = 0; nextVal < alphabetSize; nextVal++) { // compute p_next double p_next = (double) nextCount[nextVal] / (double) observations; for (int prevVal = 0; prevVal < base_power_k; prevVal++) { @@ -335,7 +332,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr double entRate = 0.0; double entRateCont = 0.0; - for (int nextVal = 0; nextVal < base; nextVal++) { + for (int nextVal = 0; nextVal < alphabetSize; nextVal++) { for (int prevVal = 0; prevVal < base_power_k; prevVal++) { // compute p_prev double p_prev = (double) pastCount[prevVal] / (double) observations; @@ -389,7 +386,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr // Initialise and store the current previous value for each column int prevVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[p]; } @@ -414,7 +411,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr } // Update the previous value: prevVal -= maxShiftedValue[states[t-k]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[t]; } average = average/(double) (timeSteps - k); @@ -423,7 +420,6 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr } - @Override public double[][] computeLocalFromPreviousObservations(int states[][]){ int rows = states.length; int columns = states[0].length; @@ -439,7 +435,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr for (int c = 0; c < columns; c++) { prevVal[c] = 0; for (int p = 0; p < k; p++) { - prevVal[c] *= base; + prevVal[c] *= alphabetSize; prevVal[c] += states[p][c]; } } @@ -465,7 +461,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr } // Update the previous value: prevVal[c] -= maxShiftedValue[states[r-k][c]]; - prevVal[c] *= base; + prevVal[c] *= alphabetSize; prevVal[c] += states[r][c]; } } @@ -475,7 +471,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr } - @Override + public double[][][] computeLocalFromPreviousObservations(int states[][][]){ int timeSteps = states.length; int agentRows = states[0].length; @@ -493,7 +489,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr for (int c = 0; c < agentColumns; c++) { prevVal[r][c] = 0; for (int p = 0; p < k; p++) { - prevVal[r][c] *= base; + prevVal[r][c] *= alphabetSize; prevVal[r][c] += states[p][r][c]; } } @@ -521,7 +517,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr } // Update the previous value: prevVal[r][c] -= maxShiftedValue[states[t-k][r][c]]; - prevVal[r][c] *= base; + prevVal[r][c] *= alphabetSize; prevVal[r][c] += states[t][r][c]; } } @@ -531,7 +527,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr return localActive; } - @Override + public double[] computeLocalFromPreviousObservations(int states[][], int col){ int rows = states.length; //int columns = states[0].length; @@ -546,7 +542,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr int prevVal = 0; prevVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[p][col]; } int nextVal; @@ -570,7 +566,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr } // Update the previous value: prevVal -= maxShiftedValue[states[r-k][col]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[r][col]; } average = average/(double) (rows - k); @@ -579,7 +575,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr } - @Override + public double[] computeLocalFromPreviousObservations(int states[][][], int agentIndex1, int agentIndex2){ int timeSteps = states.length; @@ -595,7 +591,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr int prevVal = 0; prevVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[p][agentIndex1][agentIndex2]; } int nextVal; @@ -619,7 +615,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr } // Update the previous value: prevVal -= maxShiftedValue[states[t-k][agentIndex1][agentIndex2]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[t][agentIndex1][agentIndex2]; } average = average/(double) (timeSteps - k); @@ -709,14 +705,14 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr MatrixUtils.fill(prevValues, prevVal, t_prev, numberOfSamplesPrev); t_prev += numberOfSamplesPrev; } - for (int nextVal = 0; nextVal < base; nextVal++) { + for (int nextVal = 0; nextVal < alphabetSize; nextVal++) { int numberOfSamplesNext = nextCount[nextVal]; MatrixUtils.fill(nextValues, nextVal, t_next, numberOfSamplesNext); t_next += numberOfSamplesNext; } ActiveInformationCalculatorDiscrete ais2; - ais2 = new ActiveInformationCalculatorDiscrete(base, k); + ais2 = new ActiveInformationCalculatorDiscrete(alphabetSize, k); ais2.initialise(); ais2.observations = observations; ais2.pastCount = pastCount; @@ -754,7 +750,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr } return new ChiSquareMeasurementDistribution(average, observations, - (base - 1) * (base_power_k - 1)); + (alphabetSize - 1) * (base_power_k - 1)); } /** @@ -767,7 +763,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr double miCont = 0.0; System.out.println("nextVal p(next) prevVal p(prev) p(joint) logTerm localVal"); - for (int nextVal = 0; nextVal < base; nextVal++) { + for (int nextVal = 0; nextVal < alphabetSize; nextVal++) { // compute p_next double p_next = (double) nextCount[nextVal] / (double) observations; for (int prevVal = 0; prevVal < base_power_k; prevVal++) { @@ -811,7 +807,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr public int computePastValue(int[] x, int t) { int pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += x[t - k + 1 + p]; } return pastVal; @@ -835,7 +831,7 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr public int computePastValue(int[][] data, int column, int t) { int pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += data[t - k + 1 + p][column]; } return pastVal; @@ -863,9 +859,27 @@ public class ActiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscr int agentColumn, int t) { int pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += data[t - k + 1 + p][agentRow][agentColumn]; } return pastVal; } + + @Override + public void setObservations(Object[] observations) throws Exception { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'setObservations'"); + } + + @Override + public void startAddObservations() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'startAddObservations'"); + } + + @Override + public void finaliseAddObservations() throws Exception { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'finaliseAddObservations'"); + } } diff --git a/java/source/infodynamics/measures/discrete/BlockEntropyCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/BlockEntropyCalculatorDiscrete.java index 40bdda3..29eb1fb 100755 --- a/java/source/infodynamics/measures/discrete/BlockEntropyCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/BlockEntropyCalculatorDiscrete.java @@ -104,7 +104,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { private void resetBlocksize(int blocksize) { this.blocksize = blocksize; - base_power_blocksize = MathsUtils.power(base, blocksize); + base_power_blocksize = MathsUtils.power(alphabetSize, blocksize); if (blocksize <= 1) { throw new RuntimeException("Blocksize " + blocksize + " is not > 1 for Block Entropy Calculator"); @@ -114,14 +114,14 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { } // Create constants for tracking stateValues - maxShiftedValue = new int[base]; - for (int v = 0; v < base; v++) { - maxShiftedValue[v] = v * MathsUtils.power(base, blocksize-1); + maxShiftedValue = new int[alphabetSize]; + for (int v = 0; v < alphabetSize; v++) { + maxShiftedValue[v] = v * MathsUtils.power(alphabetSize, blocksize-1); } } public void initialise(int blocksize, int base) { - boolean baseOrBlocksizeChanged = (this.blocksize != blocksize) || (this.base != base); + boolean baseOrBlocksizeChanged = (this.blocksize != blocksize) || (this.alphabetSize != base); super.initialise(base); if (baseOrBlocksizeChanged) { @@ -148,7 +148,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { @Override public void initialise() { - initialise(blocksize, base); + initialise(blocksize, alphabetSize); } @Override @@ -163,7 +163,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { // Add the contribution from this observation stateVal += states[p]; // And shift up - stateVal *= base; + stateVal *= alphabetSize; } // 1. Now count the tuples observed from the next row onwards @@ -176,7 +176,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { // Remove the oldest observation from the state value stateVal -= maxShiftedValue[states[r-blocksize+1]]; - stateVal *= base; + stateVal *= alphabetSize; } } @@ -195,7 +195,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { // Add the contribution from this observation stateVal[c] += states[p][c]; // And shift up - stateVal[c] *= base; + stateVal[c] *= alphabetSize; } } @@ -210,12 +210,12 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { // Remove the oldest observation from the state value stateVal[c] -= maxShiftedValue[states[r-blocksize+1][c]]; - stateVal[c] *= base; + stateVal[c] *= alphabetSize; } } } - @Override + public void addObservations(int states[][][]) { int timeSteps = states.length; if (timeSteps == 0) { @@ -238,7 +238,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { // Add the contribution from this observation stateVal[r][c] += states[p][r][c]; // And shift up - stateVal[r][c] *= base; + stateVal[r][c] *= alphabetSize; } } } @@ -255,13 +255,13 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { // Remove the oldest observation from the state value stateVal[r][c] -= maxShiftedValue[states[t-blocksize+1][r][c]]; - stateVal[r][c] *= base; + stateVal[r][c] *= alphabetSize; } } } } - @Override + public void addObservations(int states[][], int col) { int rows = states.length; // increment the count of observations: @@ -273,7 +273,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { // Add the contribution from this observation stateVal += states[p][col]; // And shift up - stateVal *= base; + stateVal *= alphabetSize; } // 1. Count the tuples observed @@ -286,11 +286,11 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { // Remove the oldest observation from the state value stateVal -= maxShiftedValue[states[r-blocksize+1][col]]; - stateVal *= base; + stateVal *= alphabetSize; } } - @Override + public void addObservations(int states[][][], int agentIndex1, int agentIndex2) { int timeSteps = states.length; // increment the count of observations: @@ -302,7 +302,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { // Add the contribution from this observation stateVal += states[p][agentIndex1][agentIndex2]; // And shift up - stateVal *= base; + stateVal *= alphabetSize; } // 1. Count the tuples observed @@ -315,7 +315,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { // Remove the oldest observation from the state value stateVal -= maxShiftedValue[states[t-blocksize+1][agentIndex1][agentIndex2]]; - stateVal *= base; + stateVal *= alphabetSize; } } @@ -348,7 +348,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { return ent; } - @Override + public double[][] computeLocalFromPreviousObservations(int states[][]){ int rows = states.length; int columns = states[0].length; @@ -365,7 +365,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { stateVal[c] = 0; for (int p = 0; p < blocksize - 1; p++) { stateVal[c] += states[p][c]; - stateVal[c] *= base; + stateVal[c] *= alphabetSize; } } // StateVal just needs the next value put in before processing @@ -387,7 +387,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { // Subtract out the oldest part of the state value: stateVal[c] -= maxShiftedValue[states[r-blocksize+1][c]]; // And shift all upwards - stateVal[c] *= base; + stateVal[c] *= alphabetSize; } } average = average/(double) (columns * (rows - blocksize + 1)); @@ -396,7 +396,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { } - @Override + public double[][][] computeLocalFromPreviousObservations(int states[][][]){ int timeSteps = states.length; int agentRows, agentColumns; @@ -425,7 +425,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { stateVal[r][c] = 0; for (int p = 0; p < blocksize - 1; p++) { stateVal[r][c] += states[p][r][c]; - stateVal[r][c] *= base; + stateVal[r][c] *= alphabetSize; } } } @@ -449,7 +449,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { // Subtract out the oldest part of the state value: stateVal[r][c] -= maxShiftedValue[states[t-blocksize+1][r][c]]; // And shift all upwards - stateVal[r][c] *= base; + stateVal[r][c] *= alphabetSize; } } } @@ -459,7 +459,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { } - @Override + public double[] computeLocalFromPreviousObservations(int states[][], int col){ int rows = states.length; //int columns = states[0].length; @@ -476,7 +476,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { int stateVal = 0; for (int p = 0; p < blocksize - 1; p++) { stateVal += states[p][col]; - stateVal *= base; + stateVal *= alphabetSize; } // StateVal just needs the next value put in before processing @@ -496,7 +496,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { // Subtract out the oldest part of the state value: stateVal -= maxShiftedValue[states[r-blocksize+1][col]]; // And shift all upwards - stateVal *= base; + stateVal *= alphabetSize; } average = average/(double) (rows - blocksize + 1); @@ -504,7 +504,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { } - @Override + public double[] computeLocalFromPreviousObservations(int states[][][], int agentIndex1, int agentIndex2){ int timeSteps = states.length; //int columns = states[0].length; @@ -521,7 +521,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { int stateVal = 0; for (int p = 0; p < blocksize - 1; p++) { stateVal += states[p][agentIndex1][agentIndex2]; - stateVal *= base; + stateVal *= alphabetSize; } // StateVal just needs the next value put in before processing @@ -541,7 +541,7 @@ public class BlockEntropyCalculatorDiscrete extends EntropyCalculatorDiscrete { // Subtract out the oldest part of the state value: stateVal -= maxShiftedValue[states[t-blocksize+1][agentIndex1][agentIndex2]]; // And shift all upwards - stateVal *= base; + stateVal *= alphabetSize; } average = average/(double) (timeSteps - blocksize + 1); diff --git a/java/source/infodynamics/measures/discrete/CombinedActiveEntRateCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/CombinedActiveEntRateCalculatorDiscrete.java index 56ee18d..d59505c 100755 --- a/java/source/infodynamics/measures/discrete/CombinedActiveEntRateCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/CombinedActiveEntRateCalculatorDiscrete.java @@ -32,7 +32,7 @@ import infodynamics.utils.MatrixUtils; * and typical usage pattern. *

* - * TODO Make this inherit from {@link SingleAgentMeasureDiscreteInContextOfPastCalculator} + * TODO Make this inherit from {@link UnivariateMeasureDiscreteInContextOfPastCalculator} * like {@link ActiveInformationCalculatorDiscrete} and fix the Javadocs * * @author Joseph Lizier (email, diff --git a/java/source/infodynamics/measures/discrete/ConditionalTransferEntropyCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/ConditionalTransferEntropyCalculatorDiscrete.java index c9e8aef..9f8d13b 100644 --- a/java/source/infodynamics/measures/discrete/ConditionalTransferEntropyCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/ConditionalTransferEntropyCalculatorDiscrete.java @@ -242,7 +242,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete public void initialise(int base, int history, int numOtherInfoContributors, int base_others) { - boolean paramsChanged = (this.base != base) || (k != history) || + boolean paramsChanged = (this.alphabetSize != base) || (k != history) || (this.numOtherInfoContributors != numOtherInfoContributors) || (this.base_others != base_others); super.initialise(base, history); @@ -275,7 +275,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete @Override public void initialise(){ - initialise(base, k, numOtherInfoContributors, base_others); + initialise(alphabetSize, k, numOtherInfoContributors, base_others); } /** @@ -313,7 +313,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete // Initialise and store the current previous value int pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += dest[p]; } @@ -336,7 +336,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete // Update the previous value: if (k > 0) { pastVal -= maxShiftedValue[dest[r-k]]; - pastVal *= base; + pastVal *= alphabetSize; pastVal += dest[r]; } } @@ -386,7 +386,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete // Initialise and store the current previous value int pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += dest[p]; } @@ -404,7 +404,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete // Update the previous value: if (k > 0) { pastVal -= maxShiftedValue[dest[r-k]]; - pastVal *= base; + pastVal *= alphabetSize; pastVal += dest[r]; } } @@ -468,7 +468,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete for (int c = 0; c < columns; c++) { pastVal[c] = 0; for (int p = 0; p < k; p++) { - pastVal[c] *= base; + pastVal[c] *= alphabetSize; pastVal[c] += states[p][c]; } } @@ -494,7 +494,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete // Update the previous value: if (k > 0) { pastVal[c] -= maxShiftedValue[states[r-k][c]]; - pastVal[c] *= base; + pastVal[c] *= alphabetSize; pastVal[c] += states[r][c]; } } @@ -551,7 +551,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete // Initialise and store the current previous value for each column int pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += states[p][destCol]; } @@ -575,7 +575,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete // Update the previous value: if (k > 0) { pastVal -= maxShiftedValue[states[r-k][destCol]]; - pastVal *= base; + pastVal *= alphabetSize; pastVal += states[r][destCol]; } } @@ -591,8 +591,8 @@ public class ConditionalTransferEntropyCalculatorDiscrete double meanSqLocals = 0; for (int othersVal = 0; othersVal < this.base_power_num_others; othersVal++) { for (int pastVal = 0; pastVal < base_power_k; pastVal++) { - for (int destVal = 0; destVal < base; destVal++) { - for (int sourceVal = 0; sourceVal < base; sourceVal++) { + for (int destVal = 0; destVal < alphabetSize; destVal++) { + for (int sourceVal = 0; sourceVal < alphabetSize; sourceVal++) { // Compute TE contribution: if (sourceDestPastOthersCount[sourceVal][destVal][pastVal][othersVal] != 0) { /* Double check: should never happen @@ -650,7 +650,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete // Reconstruct the source values (not necessarily in order) int[] sourceValues = new int[observations]; int t_s = 0; - for (int sourceVal = 0; sourceVal < base; sourceVal++) { + for (int sourceVal = 0; sourceVal < alphabetSize; sourceVal++) { // Count up the number of times this source value was observed: int numberOfSamples = 0; for (int pastVal = 0; pastVal < base_power_k; pastVal++) { @@ -683,7 +683,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete MatrixUtils.fill(othersValues, othersVal, t_o, pastOthersCount[pastVal][othersVal]); t_o += pastOthersCount[pastVal][othersVal]; - for (int destVal = 0; destVal < base; destVal++) { + for (int destVal = 0; destVal < alphabetSize; destVal++) { MatrixUtils.fill(destValues, destVal, t_d, destPastOthersCount[destVal][pastVal][othersVal]); t_d += destPastOthersCount[destVal][pastVal][othersVal]; @@ -692,7 +692,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete } // TODO stop using deprecated method - ConditionalTransferEntropyCalculatorDiscrete cte = newInstance(base, k, numOtherInfoContributors); + ConditionalTransferEntropyCalculatorDiscrete cte = newInstance(alphabetSize, k, numOtherInfoContributors); cte.initialise(); cte.observations = observations; cte.pastOthersCount = pastOthersCount; @@ -733,7 +733,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete } return new ChiSquareMeasurementDistribution(average, observations, - (base - 1)*(base - 1)*(base_power_k*base_power_num_others)); + (alphabetSize - 1)*(alphabetSize - 1)*(base_power_k*base_power_num_others)); } /** @@ -804,7 +804,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete for (int c = 0; c < columns; c++) { pastVal[c] = 0; for (int p = 0; p < k; p++) { - pastVal[c] *= base; + pastVal[c] *= alphabetSize; pastVal[c] += states[p][c]; } } @@ -834,7 +834,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete // Update the previous value: if (k > 0) { pastVal[c] -= maxShiftedValue[states[r-k][c]]; - pastVal[c] *= base; + pastVal[c] *= alphabetSize; pastVal[c] += states[r][c]; } } @@ -905,7 +905,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete int pastVal = 0; pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += states[p][destCol]; } int destVal, sourceVal, othersVal; @@ -932,7 +932,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete // Update the previous value: if (k > 0) { pastVal -= maxShiftedValue[states[r-k][destCol]]; - pastVal *= base; + pastVal *= alphabetSize; pastVal += states[r][destCol]; } } @@ -975,7 +975,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete int pastVal = 0; pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += dest[p]; } int destVal, sourceVal, conditionalVal; @@ -997,7 +997,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete // Update the previous value: if (k > 0) { pastVal -= maxShiftedValue[dest[r-k]]; - pastVal *= base; + pastVal *= alphabetSize; pastVal += dest[r]; } } @@ -1033,7 +1033,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete int pastVal = 0; pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += dest[p]; } int destVal, sourceVal, conditionalsVal; @@ -1044,7 +1044,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete conditionalsVal = 0; for (int o = 0; o < conditionals[r-1].length; o++) { // Include this other contributor - conditionalsVal *= base; + conditionalsVal *= alphabetSize; conditionalsVal += conditionals[r-1][o]; } // Now compute the local value @@ -1060,7 +1060,7 @@ public class ConditionalTransferEntropyCalculatorDiscrete // Update the previous value: if (k > 0) { pastVal -= maxShiftedValue[dest[r-k]]; - pastVal *= base; + pastVal *= alphabetSize; pastVal += dest[r]; } } diff --git a/java/source/infodynamics/measures/discrete/ContextOfPastMeasureCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/ContextOfPastMeasureCalculatorDiscrete.java index 1b19801..5e095e2 100755 --- a/java/source/infodynamics/measures/discrete/ContextOfPastMeasureCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/ContextOfPastMeasureCalculatorDiscrete.java @@ -111,7 +111,7 @@ public abstract class ContextOfPastMeasureCalculatorDiscrete extends private void resetHistory(int history) { k = history; - base_power_k = MathsUtils.power(base, k); + base_power_k = MathsUtils.power(alphabetSize, k); if (k < 0) { throw new RuntimeException("History k " + history + " is not >= 0 for a ContextOfPastMeasureCalculator"); @@ -123,15 +123,15 @@ public abstract class ContextOfPastMeasureCalculatorDiscrete extends } // Create constants for tracking prevValues - maxShiftedValue = new int[base]; - for (int v = 0; v < base; v++) { - maxShiftedValue[v] = v * MathsUtils.power(base, k-1); + maxShiftedValue = new int[alphabetSize]; + for (int v = 0; v < alphabetSize; v++) { + maxShiftedValue[v] = v * MathsUtils.power(alphabetSize, k-1); } } @Override public void initialise() { - initialise(base, k); + initialise(alphabetSize, k); } /** @@ -143,7 +143,7 @@ public abstract class ContextOfPastMeasureCalculatorDiscrete extends */ public void initialise(int base, int history) { boolean baseOrHistoryChanged = false; - if ((this.base != base) || (k != history)) { + if ((this.alphabetSize != base) || (k != history)) { baseOrHistoryChanged = true; } @@ -189,7 +189,7 @@ public abstract class ContextOfPastMeasureCalculatorDiscrete extends public int computePastValue(int[] x, int t) { int pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += x[t - k + 1 + p]; } return pastVal; @@ -212,7 +212,7 @@ public abstract class ContextOfPastMeasureCalculatorDiscrete extends public int computePastValue(int[][] data, int columnNumber, int t) { int pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += data[t - k + 1 + p][columnNumber]; } return pastVal; @@ -238,7 +238,7 @@ public abstract class ContextOfPastMeasureCalculatorDiscrete extends public int computePastValue(int[][][] data, int rowNumber, int columnNumber, int t) { int pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += data[t - k + 1 + p][rowNumber][columnNumber]; } return pastVal; diff --git a/java/source/infodynamics/measures/discrete/EntropyCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/EntropyCalculatorDiscrete.java index f2efc79..6dfe84d 100755 --- a/java/source/infodynamics/measures/discrete/EntropyCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/EntropyCalculatorDiscrete.java @@ -19,6 +19,9 @@ package infodynamics.measures.discrete; import java.util.Hashtable; +import java.util.Map; +import java.util.List; +import java.util.Arrays; import infodynamics.utils.MatrixUtils; @@ -58,12 +61,27 @@ Theory' (John Wiley & Sons, New York, 1991). * www) */ public class EntropyCalculatorDiscrete extends InfoMeasureCalculatorDiscrete - implements SingleAgentMeasureDiscrete + implements UnivariateMeasureDiscrete { + // TODO -- find or calculate reasonable max value. Currently 100. protected int[] stateCount = null; // Count for i[t] + /** + * State counts in a hashtable for observations other than ints + * as well as for sparse observations + */ protected Hashtable hashedStateCount = null; + + /** + * Number of dimensions for multi-dimensional calculations + */ + protected int numDimensions = 1; + + /** + * Sizes of each dimension's alphabet + */ + protected int[] alphabetSizes = null; /** * Construct a new instance with no specified alphabet size. @@ -80,102 +98,7 @@ public class EntropyCalculatorDiscrete extends InfoMeasureCalculatorDiscrete */ public EntropyCalculatorDiscrete(int alphabetSize) { super(alphabetSize); - } - - /** - * Initialise with new alphabet size - * - * @param alphabetSize - */ - public void initialise(int alphabetSize){ - boolean sizeChange = (this.alphabetSize != alphabetSize); - super.initialise(alphabetSize); - - if (sizeChange || (stateCount == null)) { - // Create storage for counts of observations - try { - stateCount = new int[alphabetSize]; - } catch (OutOfMemoryError e) { - // Allow any Exceptions to be thrown, but catch and wrap - // Error as a RuntimeException - throw new RuntimeException("Requested memory for the alphabet size (" + - alphabetSize + ") is too large for the JVM at this time", e); - } - } else { - MatrixUtils.fill(stateCount, 0); - } - } - - @Override - public void initialise(){ - initialise(alphabetSize); - } - - @Override - public void addObservations(Object[] states) { - int rows = states.length; - // increment the count of observations: - observations += rows; - - // 1. Count the tuples observed - for (int r = 0; r < rows; r++) { - // Add to the count for this particular state: - - if (!knownIntegerRange) { - Object key = states[r]; - Integer value = hashedStateCount.getOrDefault(key, 0) + 1; - hashedStateCount.put(key, value); - continue; - } - - // TODO better way to do this?? - // obviously we can do .getClass() twice in the if statements, I think this is - // slightly more readable though. - // joe's input: - @SuppressWarnings("rawtypes") - Class objectClass = states[r].getClass(); - Integer index; - if (objectClass == String.class) { - index = Integer.parseInt((String) states[r]); - } else if (objectClass == Integer.class) { - index = (Integer) states[r]; - } else { - throw new NumberFormatException(String.format( - "Cannot parse %s as an Integer for indexing", - states[r])); - } - - // valid index, check to make sure user didn't break the alphabet size they provided. - if (index >= stateCount.length) { - // runtime exception I guess...? - // TODO joe's input: - throw new RuntimeException(String.format( - "Observation %s exceeds provided alphabet size %d", - states[r], this.alphabetSize)); - } - stateCount[index]++; - } - } - - // I added this so that computeAverageLocal works, which we were considering deprecating - // Though i think keeping the old int[] format is worthwhile for backwards compat. - // TODO joe's input: - // maybe deprecate (with computeAverageLocal) - /** - * Add observations in to our estimates of the pdfs. - * - * @param states - */ - public void addObservations(int[] states) { - int rows = states.length; - // increment the count of observations: - observations += rows; - - // 1. Count the tuples observed - for (int r = 0; r < rows; r++) { - // Add to the count for this particular state: - stateCount[states[r]]++; - } + currentState = State.SETTING_PROPERTIES; } /** @@ -185,8 +108,30 @@ public class EntropyCalculatorDiscrete extends InfoMeasureCalculatorDiscrete * @return count of observations of the given state */ public int getStateCount(int stateVal) { + // stateCount could have overflowed + if (stateCount == null) { + return hashedStateCount.get((Integer) stateVal); + } return stateCount[stateVal]; } + + /** + * Return the current count for the given value + * + * @param stateVal given value + * @return count of observations of the given state + */ + public int getStateCount(Object stateVal) { + if (stateCount == null) { + return hashedStateCount.get(stateVal); + } else if (stateVal instanceof String) { + int index = Integer.parseInt((String) stateVal); + return stateCount[index]; + } else { + int index = (Integer) stateVal; + return stateCount[index]; + } + } /** * Return the current probability for the given value @@ -197,30 +142,385 @@ public class EntropyCalculatorDiscrete extends InfoMeasureCalculatorDiscrete public double getStateProbability(int stateVal) { return (double) stateCount[stateVal] / (double) observations; } + + /** + * Initialise with new alphabet size + * + * @param alphabetSize + */ + public void initialise(int alphabetSize){ + boolean sizeChange = (this.alphabetSize != alphabetSize); + super.initialise(alphabetSize); + + // if alphabet size is unknown, use large but managable array + // only moving to hash table for arrays exceeding this temp limit. + int temp = alphabetSize; + if (temp == -1) { + // TODO -- This is where we set the reasonable max value. See top of class. + temp = 100; + } + + if (sizeChange || stateCount == null) { + // Create storage for counts of observations + try { + stateCount = new int[temp]; + } catch (OutOfMemoryError e) { + // Allow any Exceptions to be thrown, but catch and wrap + // Error as a RuntimeException + throw new RuntimeException("Requested memory for the alphabet size (" + + alphabetSize + ") is too large for the JVM at this time", e); + } + } else { + MatrixUtils.fill(stateCount, 0); + } + hashedStateCount = new Hashtable<>(); + currentState = State.INITIALISED; + } + + @Override + public void initialise(){ + initialise(alphabetSize); + } + + @Override + public void setProperty(String propertyName, String propertyValue) throws Exception { + // TODO -- set states here too, enforce correct workflow + // I believe this has been done + if (currentState != State.SETTING_PROPERTIES) { + stateCount = null; + hashedStateCount = new Hashtable<>(); + knownIntegerRange = false; + alphabetSizes = null; + numDimensions = 1; + currentState = State.SETTING_PROPERTIES; + + // TODO -- This is where we set the reasonable max value. See top of class. + alphabetSize = 100; + } + + switch(propertyName.toUpperCase()) { + case "NUM_DIMENSIONS": + try { + this.numDimensions = Integer.parseInt(propertyValue); + if (numDimensions < 0) { + throw new NumberFormatException("propertyValue for NUM_DIMENSIONS must be at least 0."); + } + } catch (NumberFormatException e) { + throw new NumberFormatException("propertyValue for NUM_DIMENSIONS must be interpretable as an integer."); + } + break; + case "ALPHABET_SIZES": + /* + * Currently accepts '1,2,3' or '[1,2,3]' formats, as this seemed + * easiest for importing data as well as manual input. + * '1, 2, 3' and '[1, 2, 3]' should also work with parseInt, though I'm unsure. + */ + propertyValue.replaceFirst("[", ""); + propertyValue.replaceFirst("]", ""); + String[] temp = propertyValue.split(","); + this.alphabetSizes = new int[temp.length]; + for (int i = 0; i < temp.length; i++) { + try { + alphabetSizes[i] = Integer.parseInt(temp[i]); + } catch (NumberFormatException e) { + throw new NumberFormatException("propertyValue for ALPHABET_SIZES must be interpretable as an integer array.\n" + + "Input should look like [1,2,3]"); + } + } + break; + default: + super.setProperty(propertyName, propertyValue); + break; + } + } + + public void addObservations(Object[] states) throws NumberFormatException, RuntimeException { + // if user has set numDimensions, they intend for multi-dimensional, and + // should not be using this function + if (numDimensions != 1) { + throw new RuntimeException( + "numDimensions was not 1. " + + "If you intend to use multi-dimensional observations, use addObservations(Object[][] states)." + ); + } + + if (currentState == State.COMPUTING || + currentState == State.SETTING_PROPERTIES) { + initialise(); + } + currentState = State.ADDING_OBSERVATIONS; + + int rows = states.length; + // increment the count of observations: + observations += rows; + + // 1. Count the tuples observed + for (int r = 0; r < rows; r++) { + // Add to the count for this particular state: + + if (!hashedStateCount.isEmpty()) { + Object key = states[r]; + Integer value = hashedStateCount.getOrDefault(key, 0) + 1; + hashedStateCount.put(key, value); + continue; + } + + Integer index = this.alphabetSize; + if (states[r] instanceof String ) { + if (((String) states[r]).matches("[0-9]+")) { + index = Integer.parseInt((String) states[r]); + } else if (!knownIntegerRange) { + // First observation ever is non-integer string, right to hashtable + hashedStateCount.put((Object) states[r], 1); + stateCount = null; + continue; + } + } else if (states[r] instanceof Integer) { + index = (Integer) states[r]; + } else { + throw new NumberFormatException( + "Cannot parse " + states[r] + " as an Integer for indexing."); + } + + // valid index, check to make sure user didn't break the alphabet size they provided. + if (knownIntegerRange && index >= alphabetSize) { + throw new RuntimeException("Observation " + states[r] + + " exceeds provided alphabet size " + alphabetSize); + } + + // if array is still a managable size... + if (index < stateCount.length) { + stateCount[index]++; + } else { + // otherwise array has grown too large, move to hash table. + for (int i = 0; i < stateCount.length; i++) { + hashedStateCount.put(i, stateCount[i]); + } + hashedStateCount.put(index, 1); + stateCount = null; + } + } + } + + /** + * Add observations in to our estimates of the pdfs. + * + * @param states + */ + public void addObservations(int[] states) { + + // if user has set numDimensions, they intend for multi-dimensional, and + // should not be using this function + if (numDimensions != 1) { + throw new RuntimeException( + "numDimensions was not 1. " + + "If you intend to use multi-dimensional observations, use addObservations(int[][] states)." + ); + } + + if (currentState == State.COMPUTING || + currentState == State.SETTING_PROPERTIES) { + initialise(); + } + currentState = State.ADDING_OBSERVATIONS; + + int rows = states.length; + // increment the count of observations: + observations += rows; + + // 1. Count the tuples observed + for (int r = 0; r < rows; r++) { + + if (!hashedStateCount.isEmpty()) { + Object key = states[r]; + Integer value = hashedStateCount.getOrDefault(key, 0) + 1; + hashedStateCount.put(key, value); + continue; + } + + Integer index = states[r]; + // check to make sure user didn't break the alphabet size they provided. + if (knownIntegerRange && index >= this.alphabetSize) { + throw new RuntimeException("Observation " + states[r] + + " exceeds provided alphabet size " + alphabetSize); + } + + // if array is still a managable size... + if (index < alphabetSize) { + stateCount[index]++; + } else { + // Otherwise array has grown too large, move to hash table. + hashedStateCount = new Hashtable<>(); + for (int i = 0; i < stateCount.length; i++) { + if (stateCount[i] != 0) { + hashedStateCount.put(i, stateCount[i]); + } + } + hashedStateCount.put(index, 1); + stateCount = null; + } + } + } + + /** + * This method is intended for multi-dimensional use, and adds the observations + * into our estimates of the pdfs. + * + * @param states - the observations of all dimensions at each time step + * states[i][j] represents the ith observed state of the jth dimension. + * states[i] is the array of observations at time step i. + */ + @Override + public void addObservations(int[][] states) throws RuntimeException { + + // ensure correct number of dimensions are provided + for (int i = 0; i < states.length; i++) { + if (states[i].length != numDimensions) { + throw new RuntimeException(String.format( + "Incorrect number of dimensions were given. Expected %d got %d.", numDimensions, states[i].length)); + } + } + + if (currentState == State.COMPUTING || + currentState == State.SETTING_PROPERTIES) { + initialise(); + } + currentState = State.ADDING_OBSERVATIONS; + + + // Unwrap unecessary single dimensional arrays, allows additional calls + // to the single dimensional version without issue. + if (numDimensions == 1) { + for (int i = 0; i < states.length; i++) { + this.stateCount[i] = states[i][0]; + } + return; + } + + int[] result; + if (alphabetSizes != null) { + result = computeCombinedValues(states, alphabetSizes, alphabetSize); + } else { + result = computeCombinedValues(states, alphabetSize); + } + + for (int i = 0; i < result.length; i++) { + this.stateCount[i] += result[i]; + } + } + + /** + * This method is intended for multi-dimensional use, and adds the observations + * into our estimates of the pdfs. + * + * @param states - the observations of all dimensions at each time step + */ + public void addObservations(Object[][] states) { + + // ensure correct number of dimensions are provided + for (int i = 0; i < states.length; i++) { + if (states[i].length != numDimensions) { + throw new RuntimeException(String.format( + "Incorrect number of dimensions were given. Expected %d got %d.", numDimensions, states[i].length)); + } + } + + if (currentState == State.COMPUTING || + currentState == State.SETTING_PROPERTIES) { + initialise(); + } + currentState = State.ADDING_OBSERVATIONS; + + // Unwrap unecessary single dimensional arrays, allows additional calls + // to the single dimensional version without issue. + if (numDimensions == 1) { + Object[] temp = new Object[states.length]; + for (int i = 0; i < states.length; i++) { + temp[i] = states[i][0]; + } + addObservations(temp); + return; + } + + for (int i = 0; i < states.length; i++) { + List key = Arrays.asList(states[i]); + Integer value = hashedStateCount.getOrDefault(key, 0) + 1; + hashedStateCount.put(key, value); + } + } + + protected int[] computeCombinedValues(int[][] separatedValues, int maxSize) throws RuntimeException { + int[] sizes = new int[numDimensions]; + MatrixUtils.fill(sizes, alphabetSize); + return computeCombinedValues(separatedValues, sizes, maxSize); + } + + // TODO -- move to MatrixUtils. + protected int[] computeCombinedValues(int[][] separateValues, int[] alphabetSizes, int maxSize) throws RuntimeException { + // Make sure we won't get any overflow here + if (MatrixUtils.combinedValuesOverflow(numDimensions, alphabetSize)) { + // multiplier has overflown + throw new RuntimeException("Too many numDimensions " + numDimensions + " for the given alphabetSize " + alphabetSize + + " for this call to computeCombinedValues"); + } + + int size = 1; + for (int s : alphabetSizes) { + size *= s; + } + + if (size >= maxSize) { + throw new RuntimeException("Size of combined observations exceeds capacity."); + } + + int[] combinedValues = new int[size]; + for (int r = 0; r < separateValues.length; r++) { + if (separateValues[r].length != alphabetSizes.length) { + throw new RuntimeException("alphabetSize and given input size do not match"); + } + int combinedRowValue = 0; + int multiplier = 1; + for (int c = numDimensions - 1; c >= 0; c--) { + // check alphabet size restriction is maintained. + if (separateValues[r][c] >= alphabetSizes[r]) { + throw new RuntimeException("input value " + separateValues[r][c] + + " exceeded alphabet size" + alphabetSizes[c]); + } + combinedRowValue += separateValues[r][c] * multiplier; + multiplier *= alphabetSizes[r]; + } + combinedValues[r] = combinedRowValue; + } + return combinedValues; + } + + @Override + public void setObservations(Object[] observations) throws Exception { + this.observations = observations.length; + this.addObservations(observations); + this.finaliseAddObservations(); + } + @Override public double computeAverageLocalOfObservations() { double ent = 0.0; - double entCont = 0.0; - + double p_state; max = 0; min = 0; - for (int stateVal = 0; stateVal < alphabetSize; stateVal++) { - // compute p_state - double p_state = (double) stateCount[stateVal] / (double) observations; - if (p_state > 0.0) { - // Entropy takes the negative log: - double localValue = - Math.log(p_state) / log_2; - entCont = p_state * localValue; - if (localValue > max) { - max = localValue; - } else if (localValue < min) { - min = localValue; - } - } else { - entCont = 0.0; + currentState = State.COMPUTING; + + if (hashedStateCount.isEmpty()) { + for (int count: stateCount) { + // compute p_state + p_state = (double) count / (double) observations; + ent += computeEntropyCont(p_state); + } + } else { + for (Map.Entry entry : hashedStateCount.entrySet()) { + p_state = (double) entry.getValue() / (double) observations; + ent += computeEntropyCont(p_state); } - ent += entCont; } average = ent; @@ -228,7 +528,33 @@ public class EntropyCalculatorDiscrete extends InfoMeasureCalculatorDiscrete } @Override - public double[] computeLocalFromPreviousObservations(int states[]){ + public final double computeAverageLocal(int states[]) throws Exception { + if (states.length == 0) { + throw new RuntimeException("States cannot be empty."); + } + addObservations(states); + return computeAverageLocalOfObservations(); + } + + protected double computeEntropyCont(double p_state) { + double entCont = 0.0; + if (p_state > 0.0) { + // Entropy takes the negative log: + double localValue = - Math.log(p_state) / log_2; + entCont = p_state * localValue; + if (localValue > max) { + max = localValue; + } else if (localValue < min) { + min = localValue; + } + } + return entCont; + } + + @Override + public double[] computeLocalFromPreviousObservations(int states[]) { + + this.currentState = State.COMPUTING; int rows = states.length; double[] localEntropy = new double[rows]; @@ -250,46 +576,6 @@ public class EntropyCalculatorDiscrete extends InfoMeasureCalculatorDiscrete average = average/(double) rows; return localEntropy; } - - @Override // maybe deprecate - public final double computeAverageLocal(int states[]) throws Exception { - initialise(); - startAddObservations(); - addObservations(states); - finaliseAddObservations(); - return computeAverageLocalOfObservations(); - } - - - @Override - public void setProperty(String propertyName, String propertyValue) throws Exception { - // TODO - I think this should just be the super call, as this class has no new properties. - // joe's input: - - switch(propertyName.toLowerCase()) { - case ALPHABET_SIZE: - this.alphabetSize = Integer.parseInt(propertyValue); - break; - case MAX_ALPHA_SIZE_TO_STORE: - this.maxAlphabetSize = Integer.parseInt(propertyValue); - break; - case KNOWN_INTEGER_RANGE: - this.knownIntegerRange = Boolean.parseBoolean(propertyValue); - break; - default: - // Assume it's a property of parent class - super.setProperty(propertyName, propertyValue); - break; - } - - } - - @Override - public void setObservations(Object[] observations) throws Exception { - this.observations = observations.length; - this.addObservations(observations); - this.finaliseAddObservations(); - } /* *********************************************************************** @@ -298,348 +584,29 @@ public class EntropyCalculatorDiscrete extends InfoMeasureCalculatorDiscrete *********************************************************************** */ + // TODO protected duplicates, keep public call, that does the same as private. @Override @Deprecated public void startAddObservations() { - // reinitialise if already finalised if (currentState == State.COMPUTING) { initialise(); } this.currentState = State.ADDING_OBSERVATIONS; - } @Override @Deprecated public void finaliseAddObservations() throws Exception { - if (observations == 0) { - // TODO better error message. maybe not runtimeExc? - // joe's input: - throw new RuntimeException("0 observations not allowed."); - } - - // I actually think this is useless? It shouldn't ever get here without - // throwing the error above. if (currentState == State.SETTING_PROPERTIES) { throw new RuntimeException("Estimator should be initialised before finalised..."); } - this.currentState = State.COMPUTING; - } + if (observations == 0) { + throw new RuntimeException("Must have some observations to finalise."); + } - @Override - @Deprecated - public void addObservations(int states[][]) { - int rows = states.length; - int columns = states[0].length; - // increment the count of observations: - observations += rows * columns; - - // 1. Count the tuples observed - for (int r = 0; r < rows; r++) { - for (int c = 0; c < columns; c++) { - // Add to the count for this particular state: - stateCount[states[r][c]]++; - } - } - } - - @Override - @Deprecated - public void addObservations(int states[][][]) { - int timeSteps = states.length; - if (timeSteps == 0) { - return; - } - int agentRows = states[0].length; - if (agentRows == 0) { - return; - } - int agentColumns = states[0][0].length; - // increment the count of observations: - observations += timeSteps * agentRows * agentColumns; - - // 1. Count the tuples observed - for (int t = 0; t < timeSteps; t++) { - for (int i = 0; i < agentRows; i++) { - for (int j = 0; j < agentColumns; j++) { - // Add to the count for this particular state: - stateCount[states[t][i][j]]++; - } - } - } - } - - @Override - @Deprecated - public void addObservations(int states[][], int agentNumber) { - int rows = states.length; - // increment the count of observations: - observations += rows; - - // 1. Count the tuples observed - for (int r = 0; r < rows; r++) { - // Add to the count for this particular state: - stateCount[states[r][agentNumber]]++; - } - } - - @Override - @Deprecated - public void addObservations(int states[][][], int agentIndex1, int agentIndex2) { - int timeSteps = states.length; - // increment the count of observations: - observations += timeSteps; - - // 1. Count the tuples observed - for (int r = 0; r < timeSteps; r++) { - // Add to the count for this particular state: - stateCount[states[r][agentIndex1][agentIndex2]]++; - } - } - - @Override - @Deprecated - public final double computeAverageLocal(int states[][]) { - - initialise(); - startAddObservations(); - addObservations(states); this.currentState = State.COMPUTING; - return computeAverageLocalOfObservations(); } - - @Override - @Deprecated - public final double computeAverageLocal(int states[][][]) { - initialise(); - startAddObservations(); - addObservations(states); - this.currentState = State.COMPUTING; - return computeAverageLocalOfObservations(); - } - - @Override - @Deprecated - public final double[] computeLocal(int states[][], int col) { - initialise(); - startAddObservations(); - addObservations(states, col); - this.currentState = State.COMPUTING; - return computeLocalFromPreviousObservations(states, col); - } - - @Override - @Deprecated - public final double[] computeLocal(int states[][][], - int agentIndex1, int agentIndex2) { - initialise(); - startAddObservations(); - addObservations(states, agentIndex1, agentIndex2); - this.currentState = State.COMPUTING; - return computeLocalFromPreviousObservations(states, agentIndex1, agentIndex2); - } - - @Override - @Deprecated - public final double computeAverageLocal(int states[][], int col) { - initialise(); - startAddObservations(); - addObservations(states, col); - this.currentState = State.COMPUTING; - return computeAverageLocalOfObservations(); - } - - @Override - @Deprecated - public final double computeAverageLocal(int states[][][], int agentIndex1, int agentIndex2) { - initialise(); - startAddObservations(); - addObservations(states, agentIndex1, agentIndex2); - this.currentState = State.COMPUTING; - return computeAverageLocalOfObservations(); - } - - @Override - @Deprecated - public double[][] computeLocalFromPreviousObservations(int states[][]){ - int rows = states.length; - int columns = states[0].length; - - double[][] localEntropy = new double[rows][columns]; - average = 0; - max = 0; - min = 0; - for (int r = 0; r < rows; r++) { - for (int c = 0; c < columns; c++) { - double p_state = (double) stateCount[states[r][c]] / (double) observations; - // Entropy takes the negative log: - localEntropy[r][c] = - Math.log(p_state) / log_2; - average += localEntropy[r][c]; - if (localEntropy[r][c] > max) { - max = localEntropy[r][c]; - } else if (localEntropy[r][c] < min) { - min = localEntropy[r][c]; - } - } - } - average = average/(double) (columns * rows); - - return localEntropy; - - } - - @Override - @Deprecated - public double[][][] computeLocalFromPreviousObservations(int states[][][]){ - int timeSteps = states.length; - int agentRows, agentColumns; - if (timeSteps == 0) { - agentRows = 0; - agentColumns = 0; - } else { - agentRows = states[0].length; - if (agentRows == 0) { - agentColumns = 0; - } else { - agentColumns = states[0][0].length; - } - } - - double[][][] localEntropy = new double[timeSteps][agentRows][agentColumns]; - average = 0; - max = 0; - min = 0; - for (int r = 0; r < timeSteps; r++) { - for (int i = 0; i < agentRows; i++) { - for (int j = 0; j < agentColumns; j++) { - double p_state = (double) stateCount[states[r][i][j]] / (double) observations; - // Entropy takes the negative log: - localEntropy[r][i][j] = - Math.log(p_state) / log_2; - average += localEntropy[r][i][j]; - if (localEntropy[r][i][j] > max) { - max = localEntropy[r][i][j]; - } else if (localEntropy[r][i][j] < min) { - min = localEntropy[r][i][j]; - } - } - } - } - average = average/(double) (agentRows * agentColumns * timeSteps); - - return localEntropy; - - } - - @Override - @Deprecated - public double[] computeLocalFromPreviousObservations(int states[][], int agentNumber){ - int rows = states.length; - //int columns = states[0].length; - - double[] localEntropy = new double[rows]; - average = 0; - max = 0; - min = 0; - for (int r = 0; r < rows; r++) { - double p_state = (double) stateCount[states[r][agentNumber]] / (double) observations; - // Entropy takes the negative log: - localEntropy[r] = - Math.log(p_state) / log_2; - average += localEntropy[r]; - if (localEntropy[r] > max) { - max = localEntropy[r]; - } else if (localEntropy[r] < min) { - min = localEntropy[r]; - } - } - average = average/(double) (rows); - - return localEntropy; - - } - - @Override - @Deprecated - public double[] computeLocalFromPreviousObservations(int states[][][], int agentIndex1, int agentIndex2){ - int timeSteps = states.length; - //int columns = states[0].length; - - // Allocate for all rows even though we'll leave the first ones as zeros - double[] localEntropy = new double[timeSteps]; - average = 0; - max = 0; - min = 0; - for (int r = 0; r < timeSteps; r++) { - double p_state = (double) stateCount[states[r][agentIndex1][agentIndex2]] / (double) observations; - // Entropy takes the negative log: - localEntropy[r] = - Math.log(p_state) / log_2; - average += localEntropy[r]; - if (localEntropy[r] > max) { - max = localEntropy[r]; - } else if (localEntropy[r] < min) { - min = localEntropy[r]; - } - } - average = average/(double) (timeSteps); - - return localEntropy; - - } - - @Override - @Deprecated - public final double[] computeLocal(int states[]) { - initialise(); - startAddObservations(); - addObservations(states); - this.currentState = State.COMPUTING; - return computeLocalFromPreviousObservations(states); - } - - @Override - @Deprecated - public final double[][] computeLocal(int states[][]) { - initialise(); - startAddObservations(); - addObservations(states); - this.currentState = State.COMPUTING; - return computeLocalFromPreviousObservations(states); - } - - @Override - @Deprecated - public final double[][][] computeLocal(int states[][][]) { - initialise(); - startAddObservations(); - addObservations(states); - this.currentState = State.COMPUTING; - return computeLocalFromPreviousObservations(states); - } - - /** - * User was formerly forced to create new instances through this factory method. - * Retained for backwards compatibility. - * - * @param alphabetSize number of symbols for each variable. - * E.g. binary variables are in base-2. - * @param blocksize number of consecutive joint values to include - * in the calculation. - * @deprecated - * @return a new EntropyCalculator - */ - @Deprecated - public static EntropyCalculatorDiscrete newInstance(int alphabetSize, int blocksize) { - if (blocksize > 1) { - return BlockEntropyCalculatorDiscrete.newInstance(blocksize, alphabetSize); - } else { - return EntropyCalculatorDiscrete.newInstance(alphabetSize); - } - } - @Deprecated - public static EntropyCalculatorDiscrete newInstance(int alphabetSize) { - return new EntropyCalculatorDiscrete(alphabetSize); - } - -} +} \ No newline at end of file diff --git a/java/source/infodynamics/measures/discrete/EntropyRateCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/EntropyRateCalculatorDiscrete.java index 9080c30..f090aa2 100755 --- a/java/source/infodynamics/measures/discrete/EntropyRateCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/EntropyRateCalculatorDiscrete.java @@ -62,7 +62,7 @@ Theory' (John Wiley & Sons, New York, 1991). * @author Joseph Lizier (email, * www) */ -public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInContextOfPastCalculator { +public class EntropyRateCalculatorDiscrete extends UnivariateMeasureDiscreteInContextOfPastCalculator { /** * User was formerly forced to create new instances through this factory method. @@ -105,7 +105,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC // Initialise and store the current previous value for each column int prevVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[p]; } @@ -119,7 +119,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC pastCount[prevVal]++; // Update the previous value: prevVal -= maxShiftedValue[states[r-k]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[r]; } } @@ -136,7 +136,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC for (int c = 0; c < columns; c++) { prevVal[c] = 0; for (int p = 0; p < k; p++) { - prevVal[c] *= base; + prevVal[c] *= alphabetSize; prevVal[c] += states[p][c]; } } @@ -152,13 +152,13 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC pastCount[prevVal[c]]++; // Update the previous value: prevVal[c] -= maxShiftedValue[states[r-k][c]]; - prevVal[c] *= base; + prevVal[c] *= alphabetSize; prevVal[c] += states[r][c]; } } } - @Override + public void addObservations(int states[][][]) { int timeSteps = states.length; if (timeSteps == 0) { @@ -178,7 +178,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC for (int c = 0; c < agentColumns; c++) { prevVal[r][c] = 0; for (int p = 0; p < k; p++) { - prevVal[r][c] *= base; + prevVal[r][c] *= alphabetSize; prevVal[r][c] += states[p][r][c]; } } @@ -196,14 +196,14 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC pastCount[prevVal[r][c]]++; // Update the previous value: prevVal[r][c] -= maxShiftedValue[states[t-k][r][c]]; - prevVal[r][c] *= base; + prevVal[r][c] *= alphabetSize; prevVal[r][c] += states[t][r][c]; } } } } - @Override + public void addObservations(int states[][], int col) { int rows = states.length; // increment the count of observations: @@ -213,7 +213,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC int prevVal = 0; prevVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[p][col]; } @@ -227,12 +227,12 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC pastCount[prevVal]++; // Update the previous value: prevVal -= maxShiftedValue[states[r-k][col]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[r][col]; } } - @Override + public void addObservations(int states[][][], int agentIndex1, int agentIndex2) { int timeSteps = states.length; // increment the count of observations: @@ -242,7 +242,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC int prevVal = 0; prevVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[p][agentIndex1][agentIndex2]; } @@ -256,7 +256,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC pastCount[prevVal]++; // Update the previous value: prevVal -= maxShiftedValue[states[r-k][agentIndex1][agentIndex2]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[r][agentIndex1][agentIndex2]; } } @@ -269,7 +269,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC max = 0; min = 0; double logTerm = 0; - for (int nextVal = 0; nextVal < base; nextVal++) { + for (int nextVal = 0; nextVal < alphabetSize; nextVal++) { for (int prevVal = 0; prevVal < base_power_k; prevVal++) { // compute p_prev double p_prev = (double) pastCount[prevVal] / (double) observations; @@ -310,7 +310,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC // Initialise and store the current previous value for each column int prevVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[p]; } @@ -330,7 +330,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC } // Update the previous value: prevVal -= maxShiftedValue[states[r-k]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[r]; } average = average/(double) (rows - k); @@ -338,7 +338,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC return localEntRate; } - @Override + public double[][] computeLocalFromPreviousObservations(int states[][]){ int rows = states.length; int columns = states[0].length; @@ -354,7 +354,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC for (int c = 0; c < columns; c++) { prevVal[c] = 0; for (int p = 0; p < k; p++) { - prevVal[c] *= base; + prevVal[c] *= alphabetSize; prevVal[c] += states[p][c]; } } @@ -375,7 +375,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC } // Update the previous value: prevVal[c] -= maxShiftedValue[states[r-k][c]]; - prevVal[c] *= base; + prevVal[c] *= alphabetSize; prevVal[c] += states[r][c]; } } @@ -384,7 +384,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC return localEntRate; } - @Override + public double[][][] computeLocalFromPreviousObservations(int states[][][]){ int timeSteps = states.length; int agentRows = states[0].length; @@ -402,7 +402,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC for (int c = 0; c < agentColumns; c++) { prevVal[r][c] = 0; for (int p = 0; p < k; p++) { - prevVal[r][c] *= base; + prevVal[r][c] *= alphabetSize; prevVal[r][c] += states[p][r][c]; } } @@ -426,7 +426,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC } // Update the previous value: prevVal[r][c] -= maxShiftedValue[states[t-k][r][c]]; - prevVal[r][c] *= base; + prevVal[r][c] *= alphabetSize; prevVal[r][c] += states[t][r][c]; } } @@ -436,7 +436,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC return localEntRate; } - @Override + public double[] computeLocalFromPreviousObservations(int states[][], int col){ int rows = states.length; //int columns = states[0].length; @@ -451,7 +451,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC int prevVal = 0; prevVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[p][col]; } int nextVal; @@ -470,7 +470,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC } // Update the previous value: prevVal -= maxShiftedValue[states[r-k][col]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[r][col]; } average = average/(double) (rows - k); @@ -479,7 +479,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC } - @Override + public double[] computeLocalFromPreviousObservations(int states[][][], int agentIndex1, int agentIndex2){ int timeSteps = states.length; //int columns = states[0].length; @@ -494,7 +494,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC int prevVal = 0; prevVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[p][agentIndex1][agentIndex2]; } int nextVal; @@ -513,7 +513,7 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC } // Update the previous value: prevVal -= maxShiftedValue[states[t-k][agentIndex1][agentIndex2]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[t][agentIndex1][agentIndex2]; } average = average/(double) (timeSteps - k); @@ -521,4 +521,22 @@ public class EntropyRateCalculatorDiscrete extends SingleAgentMeasureDiscreteInC return localEntRate; } + + @Override + public void setObservations(Object[] observations) throws Exception { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'setObservations'"); + } + + @Override + public void startAddObservations() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'startAddObservations'"); + } + + @Override + public void finaliseAddObservations() throws Exception { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'finaliseAddObservations'"); + } } diff --git a/java/source/infodynamics/measures/discrete/InfoMeasureCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/InfoMeasureCalculatorDiscrete.java index 132beda..e4386eb 100755 --- a/java/source/infodynamics/measures/discrete/InfoMeasureCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/InfoMeasureCalculatorDiscrete.java @@ -71,24 +71,21 @@ public abstract class InfoMeasureCalculatorDiscrete { */ protected int observations = 0; /** - * Number of available quantised states for each variable - * (ie binary is base-2). + * Number of available quantised states for each variable. + * (ie binary is 2). */ - protected int alphabetSize = -1; // number of individual states. -1 for unknown number + protected int alphabetSize = 100; + /** - * Size of the largest alphabet to support in array based memory management before - * switching to Hashtable implementation. - */ - protected int maxAlphabetSize = 100; // largest alphabet size before moving to Hashtable memory management TODO some default value - /** - * TODO -- make better comments :) - * State indicator of what the estimator is expecting to happen next. + * Variable to keep track of where the estimator is within its workflow. + * The estimator can be in four states; Setting Properties, Initialised, + * Adding Observations, and Computing. */ protected State currentState = State.SETTING_PROPERTIES; /** - * Boolean indicating if the size of the alphabet is known to determine the use of a - * hash table implementation for memory management. + * Boolean indicating if the size of the alphabet is known to determine the + * potnetial use of a hash table implementation for memory management. */ protected boolean knownIntegerRange = false; @@ -113,6 +110,9 @@ public abstract class InfoMeasureCalculatorDiscrete { */ protected boolean debug = false; + /** + * Enum for the states of an estimator + */ protected enum State { SETTING_PROPERTIES, INITIALISED, @@ -213,15 +213,13 @@ public abstract class InfoMeasureCalculatorDiscrete { // TODO I think there are things here to do to go back to this state but I don't remember them rn // Actually do we want this here...? it should definitely be in the lower levels, so it should be // caught then... - // joe's input: + // joe's input: yes, check this at all levels. } - switch(propertyName.toLowerCase()) { + switch(propertyName.toUpperCase()) { case "ALPHABET_SIZE": this.alphabetSize = Integer.parseInt(propertyValue); - break; - case "MAX_ALPHA_SIZE_TO_STORE": - this.maxAlphabetSize = Integer.parseInt(propertyValue); + this.knownIntegerRange = true; break; case "KNOWN_INTEGER_RANGE": this.knownIntegerRange = Boolean.parseBoolean(propertyValue); diff --git a/java/source/infodynamics/measures/discrete/MultiInformationCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/MultiInformationCalculatorDiscrete.java index 56fadac..32855f5 100755 --- a/java/source/infodynamics/measures/discrete/MultiInformationCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/MultiInformationCalculatorDiscrete.java @@ -78,51 +78,51 @@ public class MultiInformationCalculatorDiscrete extends InfoMeasureCalculatorDis /** * Construct an instance * - * @base number of symbols for each variable. - * E.g. binary variables are in base-2. + * @alphabetSize number of symbols for each variable. + * E.g. binary variables are in base-2, so alphabetSize would be 2. * @numVars numbers of joint variables that multi-info * will be computed over. */ - public MultiInformationCalculatorDiscrete(int base, int numVars) { - super(base); - changeParams(base, numVars); + public MultiInformationCalculatorDiscrete(int alphabetSize, int numVars) { + super(alphabetSize); + changeParams(alphabetSize, numVars); } /** * Update the parameters using numVars * - * @param base + * @param alphabetSize * @param numVars * @return */ - private boolean changeParams(int base, int numVars) { - boolean paramsChanged = (this.base != base) || (this.numVars != numVars); + private boolean changeParams(int alphabetSize, int numVars) { + boolean paramsChanged = (this.alphabetSize != alphabetSize) || (this.numVars != numVars); this.numVars = numVars; - jointStates = MathsUtils.power(base, numVars); + jointStates = MathsUtils.power(alphabetSize, numVars); return paramsChanged; } /** - * Initialise (possible) updating the base and number of variables + * Initialise (possible) updating the alphabetSize and number of variables * - * @param base + * @param alphabetSize * @param numVars */ - public void initialise(int base, int numVars) { - boolean paramsChanged = changeParams(base, numVars); - super.initialise(base); + public void initialise(int alphabetSize, int numVars) { + boolean paramsChanged = changeParams(alphabetSize, numVars); + super.initialise(alphabetSize); if(paramsChanged || (jointCount == null)) { // Create storage for counts of observations try { jointCount = new int[jointStates]; - marginalCounts = new int[numVars][base]; + marginalCounts = new int[numVars][alphabetSize]; } 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 + + throw new RuntimeException("Requested memory for the alphabetSize " + + alphabetSize + " with " + numVars + " variables is too large for the JVM at this time", e); } } else { @@ -133,7 +133,7 @@ public class MultiInformationCalculatorDiscrete extends InfoMeasureCalculatorDis @Override public void initialise(){ - initialise(base, numVars); + initialise(alphabetSize, numVars); } /** @@ -152,7 +152,7 @@ public class MultiInformationCalculatorDiscrete extends InfoMeasureCalculatorDis for (int i = 0; i < numVars; i++) { int thisValue = states[t][i]; marginalCounts[i][thisValue]++; - jointValue *= base; + jointValue *= alphabetSize; jointValue += thisValue; } jointCount[jointValue]++; @@ -176,7 +176,7 @@ public class MultiInformationCalculatorDiscrete extends InfoMeasureCalculatorDis for (int i = 0; i < numVars; i++) { int thisValue = states[(c + groupOffsets[i] + states.length) % states.length]; marginalCounts[i][thisValue]++; - jointValue *= base; + jointValue *= alphabetSize; jointValue += thisValue; } jointCount[jointValue]++; @@ -201,7 +201,7 @@ public class MultiInformationCalculatorDiscrete extends InfoMeasureCalculatorDis for (int i = 0; i < numVars; i++) { int thisValue = states[(destinationIndex + groupOffsets[i] + states.length) % states.length]; marginalCounts[i][thisValue]++; - jointValue *= base; + jointValue *= alphabetSize; jointValue += thisValue; } jointCount[jointValue]++; @@ -227,7 +227,7 @@ public class MultiInformationCalculatorDiscrete extends InfoMeasureCalculatorDis for (int i = 0; i < numVars; i++) { int thisValue = states[t][(c + groupOffsets[i] + states.length) % states.length]; marginalCounts[i][thisValue]++; - jointValue *= base; + jointValue *= alphabetSize; jointValue += thisValue; } jointCount[jointValue]++; @@ -261,7 +261,7 @@ public class MultiInformationCalculatorDiscrete extends InfoMeasureCalculatorDis int jointValue = 0; for (int i = 0; i < numVars; i++) { prodMarginalProbs *= (double) marginalCounts[i][tuple[i]] / (double) observations; - jointValue *= base; + jointValue *= alphabetSize; jointValue += tuple[i]; } if (jointCount[jointValue] == 0) { @@ -288,7 +288,7 @@ public class MultiInformationCalculatorDiscrete extends InfoMeasureCalculatorDis miCont = jointProb * localValue; } else { // Fill out the next part of the tuple and make the recursive calls - for (int v = 0; v < base; v++) { + for (int v = 0; v < alphabetSize; v++) { tuple[fromIndex] = v; miCont += computeMiOfGivenTupleFromVarIndex(tuple, fromIndex + 1); } diff --git a/java/source/infodynamics/measures/discrete/MultiVariateInfoMeasureCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/MultiVariateInfoMeasureCalculatorDiscrete.java index 1d3f826..82ff22b 100755 --- a/java/source/infodynamics/measures/discrete/MultiVariateInfoMeasureCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/MultiVariateInfoMeasureCalculatorDiscrete.java @@ -144,7 +144,7 @@ public abstract class MultiVariateInfoMeasureCalculatorDiscrete * at many observations (first index is time, second is variable index) */ public void addObservations(int[][] states) throws Exception { - int[] jointStates = MatrixUtils.computeCombinedValues(states, base); + int[] jointStates = MatrixUtils.computeCombinedValues(states, alphabetSize); for (int t = 0; t < states.length; t++) { for (int i = 0; i < numVars; i++) { // Extract values of the 1D and the (N-1)D marginals @@ -187,7 +187,7 @@ public abstract class MultiVariateInfoMeasureCalculatorDiscrete double miCont = 0; if (fromIndex == numVars) { // The whole tuple is filled in, so compute the contribution to the MI from this tuple - int jointValue = MatrixUtils.computeCombinedValues(new int[][] {tuple}, base)[0]; + int jointValue = MatrixUtils.computeCombinedValues(new int[][] {tuple}, alphabetSize)[0]; if (jointCount[jointValue] == 0) { // This joint state does not occur, so it makes no contribution here @@ -200,7 +200,7 @@ public abstract class MultiVariateInfoMeasureCalculatorDiscrete } else { // Fill out the next part of the tuple and make the recursive calls - for (int v = 0; v < base; v++) { + for (int v = 0; v < alphabetSize; v++) { tuple[fromIndex] = v; miCont += computeForGivenTupleFromVarIndex(tuple, fromIndex + 1); } @@ -259,7 +259,7 @@ public abstract class MultiVariateInfoMeasureCalculatorDiscrete * @param tuple state of the system at a given time (index is variable number) */ protected double computeLocalValueForTuple(int[] tuple) throws Exception { - int jointValue = MatrixUtils.computeCombinedValues(new int[][] {tuple}, base)[0]; + int jointValue = MatrixUtils.computeCombinedValues(new int[][] {tuple}, alphabetSize)[0]; return computeLocalValueForTuple(tuple, jointValue); } @@ -271,7 +271,7 @@ public abstract class MultiVariateInfoMeasureCalculatorDiscrete * @param varValue value of the variable in question in the system state */ protected int computeBigMarginalState(int jointState, int varIdx, int varValue) { - int bigMarginalState = jointState - varValue*MathsUtils.power(base, numVars - varIdx - 1); + int bigMarginalState = jointState - varValue*MathsUtils.power(alphabetSize, numVars - varIdx - 1); return bigMarginalState; } diff --git a/java/source/infodynamics/measures/discrete/MutualInformationCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/MutualInformationCalculatorDiscrete.java index 7cb0c4e..2a2d417 100755 --- a/java/source/infodynamics/measures/discrete/MutualInformationCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/MutualInformationCalculatorDiscrete.java @@ -69,15 +69,16 @@ public class MutualInformationCalculatorDiscrete extends InfoMeasureCalculatorDi /** * Store the number of symbols for each variable */ - protected int base1; - protected int base2; + protected int alphabetSize1; + protected int alphabetSize2; protected int timeDiff = 0; - protected int[][] jointCount = null; // Count for (i[t-timeDiff], j[t]) tuples - protected int[] iCount = null; // Count for i[t-timeDiff] - protected int[] jCount = null; // Count for j[t] + private EntropyCalculatorDiscrete jointEntropyCalc; + private EntropyCalculatorDiscrete entropyCalc2; + private EntropyCalculatorDiscrete entropyCalc1; - protected boolean miComputed = false; + private boolean miComputed = false; + /** * Construct a new MI calculator with default bases of 2 and time difference of 0 @@ -86,7 +87,7 @@ public class MutualInformationCalculatorDiscrete extends InfoMeasureCalculatorDi * @throws Exception */ public MutualInformationCalculatorDiscrete() throws Exception { - this(2); + this(-1); } /** @@ -97,48 +98,60 @@ public class MutualInformationCalculatorDiscrete extends InfoMeasureCalculatorDi * E.g. binary variables are in base-2. * @throws Exception */ - public MutualInformationCalculatorDiscrete(int base) throws Exception { - this(base, base, 0); + public MutualInformationCalculatorDiscrete(int alphabetSize) throws Exception { + this(alphabetSize, alphabetSize, 0); } - // TODO Bring in a MutualInformationCalculatorDiscrete(int base1, int base2) constructor + // TODO Bring in a MutualInformationCalculatorDiscrete(int alphabetSize1, int alphabetSize2) constructor // but don't do this yet since it will override the previous MutualInformationCalculatorDiscrete(int base, int timeDiff) // constructor present up until v1.4 and that may lead to errors. /** * Create a new mutual information calculator * - * @param base1 number of symbols for first variable. + * @param alphabetSize1 number of symbols for first variable. * E.g. binary variables are in base-2. - * @param base2 number of symbols for second variable. + * @param alphabetSize2 number of symbols for second variable. * @param timeDiff number of time steps across which to compute * MI for given time series * @throws Exception when timeDiff < 0 */ - public MutualInformationCalculatorDiscrete(int base1, int base2, int timeDiff) throws Exception { + public MutualInformationCalculatorDiscrete(int alphabetSize1, int alphabetSize2, int timeDiff) throws Exception { // Create super object, just with first base - super(base1); + super(alphabetSize1); + + // For unknown alphabet sizes + if (alphabetSize1 == -1 || alphabetSize2 == -1) { + this.entropyCalc1 = new EntropyCalculatorDiscrete(); + this.entropyCalc2 = new EntropyCalculatorDiscrete(); + } + // For known alphabet sizes + else { + this.entropyCalc1 = new EntropyCalculatorDiscrete(alphabetSize1); + this.entropyCalc2 = new EntropyCalculatorDiscrete(alphabetSize2); + } + this.jointEntropyCalc = new EntropyCalculatorDiscrete(); - changeBases(base1, base2, timeDiff); + changeBases(alphabetSize1, alphabetSize2, timeDiff); } /** * Common code to be called when bases are changed (does not update arrays though) * - * @param base1 - * @param base2 + * @param alphabetSize1 + * @param alphabetSize2 * @param timeDiff * @throws Exception */ - private boolean changeBases(int base1, int base2, int timeDiff) throws Exception { + private boolean changeBases(int alphabetSize1, int alphabetSize2, int timeDiff) throws Exception { boolean basesChanged = false; - if ((this.base1 != base1) || (this.base2 != base2)) { + if ((this.alphabetSize1 != alphabetSize1) || (this.alphabetSize2 != alphabetSize2)) { basesChanged = true; } // Store the bases - this.base1 = base1; - this.base2 = base2; + this.alphabetSize1 = alphabetSize1; + this.alphabetSize2 = alphabetSize2; if (timeDiff < 0) { throw new Exception("timeDiff must be >= 0"); @@ -151,7 +164,7 @@ public class MutualInformationCalculatorDiscrete extends InfoMeasureCalculatorDi @Override public void initialise() { try { - initialise(base1, base2, timeDiff); + initialise(alphabetSize1, alphabetSize2, 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 @@ -162,33 +175,17 @@ public class MutualInformationCalculatorDiscrete extends InfoMeasureCalculatorDi /** * Initialise with new bases and time diff * - * @param base1 - * @param base2 + * @param alphabetSize1 + * @param alphabetSize2 * @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; - + public void initialise(int alphabetSize1, int alphabetSize2, int timeDiff) { + super.initialise(alphabetSize1); + + this.entropyCalc1.initialise(alphabetSize1); + this.entropyCalc2.initialise(alphabetSize2); + this.jointEntropyCalc.initialise(); + jointEntropyCalc.alphabetSizes = new int[] {alphabetSize1, alphabetSize2}; } /** @@ -200,95 +197,91 @@ public class MutualInformationCalculatorDiscrete extends InfoMeasureCalculatorDi */ @Override public void addObservations(int[] var1, int[] var2) { - int timeSteps = var1.length; - // int columns = states[0].length; - // increment the count of observations: - observations += (timeSteps - timeDiff); - - // 1. Count the tuples observed - int iVal, jVal; - for (int r = timeDiff; r < timeSteps; r++) { - // Add to the count for this particular pair: - iVal = var1[r-timeDiff]; - jVal = var2[r]; - jointCount[iVal][jVal]++; - iCount[iVal]++; - jCount[jVal]++; + + // I think this won't work if these aren't the same length... + // Could make it work with different lengths, unsure if this + // is ever useful. + if (var1.length != var2.length) { + throw new RuntimeException("Array lengths do not match. " + + "var1: " + var1.length + ", var2: " + var2.length); } + + // adjust var1 observations for the time difference + int[] temp1 = new int[var1.length - timeDiff]; + for (int i = 0; i < var1.length; i++) { + if (i < timeDiff) { + continue; + } + temp1[i-timeDiff] = var1[i]; + } + + // adjust var2 osbervations for the time difference + int[] temp2 = new int[var2.length - timeDiff]; + for (int i = 0; i < var2.length - timeDiff; i++) { + temp2[i-timeDiff] = var2[i]; + } + + entropyCalc1.addObservations(temp1); + entropyCalc2.addObservations(temp2); + + // Create the joint observations + int[][] jointObservations = new int[temp1.length][2]; + for (int i = 0; i < temp1.length; i++) { + jointObservations[i][0] = temp1[i]; + jointObservations[i][1] = temp2[i]; + } + + // This will throw a runtime error if format is somehow incorrect + jointEntropyCalc.addObservations(jointObservations); + observations += (var1.length - timeDiff); } - /** - * {@inheritDoc} - * - * Pairs for MI are between columns iCol and jCol, separated in time by timeDiff (i is first). - * - */ - @Override - public void addObservations(int states[][], int iCol, int jCol) { - int rows = states.length; - // int columns = states[0].length; - // increment the count of observations: - observations += (rows - timeDiff); - - // 1. Count the tuples observed - int iVal, jVal; - for (int r = timeDiff; r < rows; r++) { - // Add to the count for this particular pair: - iVal = states[r-timeDiff][iCol]; - jVal = states[r][jCol]; - jointCount[iVal][jVal]++; - iCount[iVal]++; - jCount[jVal]++; + public void addObservations(Object[] var1, Object[] var2) { + // I think this won't work if these aren't the same length... + if (var1.length != var2.length) { + throw new RuntimeException("Array lengths do not match. " + + "var1: " + var1.length + ", var2: " + var2.length); } + + // adjust var1 observations for the time difference + Object[] temp1 = new Object[var1.length - timeDiff]; + for (int i = 0; i < var1.length; i++) { + if (i < timeDiff) { + continue; + } + temp1[i-timeDiff] = var1[i]; + } + + // adjust var2 osbervations for the time difference + Object[] temp2 = new Object[var2.length - timeDiff]; + for (int i = 0; i < var2.length - timeDiff; i++) { + temp2[i-timeDiff] = var2[i]; + } + + entropyCalc1.addObservations(temp1); + entropyCalc2.addObservations(temp2); + + // Create the joint observations + Object[][] jointObservations = new Object[temp1.length][2]; + for (int i = 0; i < temp1.length; i++) { + jointObservations[i][0] = temp1[i]; + jointObservations[i][1] = temp2[i]; + } + + // This will throw a runtime error if format is somehow incorrect + jointEntropyCalc.addObservations(jointObservations); + observations += (var1.length - timeDiff); } @Override public double computeAverageLocalOfObservations() { - double mi = 0.0; - double miCont = 0.0; + double entropy1 = entropyCalc1.computeAverageLocalOfObservations(); + double entropy2 = entropyCalc2.computeAverageLocalOfObservations(); + double jointEntropy = jointEntropyCalc.computeAverageLocalOfObservations(); - max = 0; - min = 0; - double meanSqLocals = 0; - if (debug) { - System.out.println("i\tj\tp_i\tp_j\tp_joint\tlocal"); - } - for (int i = 0; i < base1; i++) { - // compute p_i - double probi = (double) iCount[i] / (double) observations; - for (int j = 0; j < base2; j++) { - // compute p_j - double probj = (double) jCount[j] / (double) observations; - // compute p(veci=i, vecj=j) - double jointProb = (double) jointCount[i][j] / (double) observations; - // Compute MI contribution: - if (jointProb * probi * probj > 0.0) { - double localValue = Math.log(jointProb / (probi * probj)) / log_2; - miCont = jointProb * localValue; - if (debug) { - System.out.printf("%d\t%d\t%.4f\t%.4f\t%.4f\t%.4f\n", - i, j, probi, probj, jointProb, localValue); - } - if (localValue > max) { - max = localValue; - } else if (localValue < min) { - min = localValue; - } - // Add this contribution to the mean - // of the squared local values - meanSqLocals += miCont * localValue; - } else { - miCont = 0.0; - } - mi += miCont; - } - } - - average = mi; - miComputed = true; - std = Math.sqrt(meanSqLocals - average * average); - - return mi; + // computeFromPreviousObservations relies on average, so I've kept that being set. + average = entropy1 + entropy2 - jointEntropy; + return average; } @Override @@ -299,8 +292,23 @@ public class MutualInformationCalculatorDiscrete extends InfoMeasureCalculatorDi return computeSignificance(newOrderings); } + // TODO Implement this method. Old code has been left for reference. + /* + * For Brad's understanding, free to delete this comment. + * This is: + * > calculate MI + * > shuffle all observations + * > recalculate MI for each permutation + * > count number of recalcs > original MI + * > p = count / numPerms + */ @Override public EmpiricalMeasurementDistribution computeSignificance(int[][] newOrderings) { + + // 1/3 temporary fix to get it to compile + // all original code is commented out below + return null; + /* double actualMI = computeAverageLocalOfObservations(); int numPermutationsToCheck = newOrderings.length; @@ -308,14 +316,14 @@ public class MutualInformationCalculatorDiscrete extends InfoMeasureCalculatorDi // Reconstruct the values of the first and second variables (not necessarily in order) int[] iValues = new int[observations]; int t_i = 0; - for (int iVal = 0; iVal < base1; iVal++) { + for (int iVal = 0; iVal < alphabetSize1; iVal++) { int numberOfSamplesI = iCount[iVal]; MatrixUtils.fill(iValues, iVal, t_i, numberOfSamplesI); t_i += numberOfSamplesI; } int[] jValues = new int[observations]; int t_j = 0; - for (int jVal = 0; jVal < base2; jVal++) { + for (int jVal = 0; jVal < alphabetSize2; jVal++) { int numberOfSamplesJ = jCount[jVal]; MatrixUtils.fill(jValues, jVal, t_j, numberOfSamplesJ); t_j += numberOfSamplesJ; @@ -323,7 +331,7 @@ public class MutualInformationCalculatorDiscrete extends InfoMeasureCalculatorDi MutualInformationCalculatorDiscrete mi2; try { - mi2 = new MutualInformationCalculatorDiscrete(base1, base2, timeDiff); + mi2 = new MutualInformationCalculatorDiscrete(alphabetSize1, alphabetSize2, timeDiff); } catch (Exception e) { // The only possible exception is if timeDiff < 0, which // it cannot be. Shut down the JVM @@ -356,6 +364,7 @@ public class MutualInformationCalculatorDiscrete extends InfoMeasureCalculatorDi measDistribution.pValue = (double) countWhereMIIsMoreSignificantThanOriginal / (double) numPermutationsToCheck; measDistribution.actualValue = actualMI; return measDistribution; + */ } @Override @@ -363,9 +372,17 @@ public class MutualInformationCalculatorDiscrete extends InfoMeasureCalculatorDi if (!miComputed) { computeAverageLocalOfObservations(); } + + int a1 = alphabetSize1; + int a2 = alphabetSize2; + if (alphabetSize1 <= -1 || alphabetSize2 == -1) { + a1 = entropyCalc1.hashedStateCount.keySet().size(); + a2 = entropyCalc2.hashedStateCount.keySet().size(); + } + return new ChiSquareMeasurementDistribution(average, observations, - (base1 - 1) * (base2 - 1)); + (a1 - 1) * (a2 - 1)); } /** @@ -381,6 +398,9 @@ public class MutualInformationCalculatorDiscrete extends InfoMeasureCalculatorDi */ public double computeLocalFromPreviousObservations(int val1, int val2) throws Exception{ + // 2/3 temporary fix to get this to compile + return 0; + /* double logTerm = ( (double) jointCount[val1][val2] ) / ( (double) jCount[val2] * (double) iCount[val1] ); @@ -392,6 +412,7 @@ public class MutualInformationCalculatorDiscrete extends InfoMeasureCalculatorDi double localMI = Math.log(logTerm) / log_2; return localMI; + */ } /** @@ -407,6 +428,9 @@ public class MutualInformationCalculatorDiscrete extends InfoMeasureCalculatorDi */ public double[] computeLocalFromPreviousObservations(int[] var1, int[] var2) throws Exception{ + // 3/3 temporary fix to get it to compile + return null; + /* if (var1.length != var2.length) { throw new Exception("var1 and var2 must have the same number of observations"); } @@ -435,74 +459,13 @@ public class MutualInformationCalculatorDiscrete extends InfoMeasureCalculatorDi average = average/(double) observations; return localMI; + */ } - - /** - * Computes local mutual information (or pointwise mutual information) - * for the given states, using pdfs built up from observations previously - * sent in via the addObservations method - * - * @param states 2D time series of observations (first index time, - * second is variable index) - * @param iCol column number for first variable - * @param jCol column number for second variable - * @return array of local mutual information values for each - * observation of (var1, var2). Note - if timeDiff > 0, then the - * return length will be var1.length - timeDiff. - */ - public double[] computeLocalFromPreviousObservations(int states[][], int iCol, int jCol){ - int rows = states.length; - //int columns = states[0].length; - // Allocate for all rows even though we'll leave the first ones as zeros - double[] localMI = new double[rows]; - int iVal, jVal; - double logTerm = 0.0; - for (int r = timeDiff; r < rows; r++) { - iVal = states[r-timeDiff][iCol]; - jVal = states[r][jCol]; - logTerm = ( (double) jointCount[iVal][jVal] ) / - ( (double) jCount[jVal] * - (double) iCount[iVal] ); - // Now account for the fact that we've - // just used counts rather than probabilities, - // and we've got two counts on the bottom - // but one count on the top: - logTerm *= (double) observations; - localMI[r] = Math.log(logTerm) / log_2; - average += localMI[r]; - if (localMI[r] > max) { - max = localMI[r]; - } else if (localMI[r] < min) { - min = localMI[r]; - } - } - average = average/(double) observations; - - return localMI; - - } - - /** - * Standalone routine to - * compute local mutual information (or pointwise mutual information) - * across a 2D spatiotemporal - * array of the states of homogeneous agents - * Return a 2D spatiotemporal array of local values. - * First history rows are zeros - * - * @param states 2D time series of observations (first index time, - * second is variable index) - * @param iCol column number for first variable - * @param jCol column number for second variable - * @return array of local mutual information values for each - * observation of (var1, var2). Note - if timeDiff > 0, then the - * return length will be var1.length - timeDiff. - */ - public double[] computeLocal(int states[][], int iCol, int jCol) { - initialise(); - addObservations(states, iCol, jCol); - return computeLocalFromPreviousObservations(states, iCol, jCol); - + // TODO -- do not implement, just remove this from the interface + @Override + public void addObservations(int[][] states, int sourceIndex, int destIndex) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'addObservations'"); } } diff --git a/java/source/infodynamics/measures/discrete/PredictiveInformationCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/PredictiveInformationCalculatorDiscrete.java index 1d46f7f..b180285 100755 --- a/java/source/infodynamics/measures/discrete/PredictiveInformationCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/PredictiveInformationCalculatorDiscrete.java @@ -80,7 +80,7 @@ import infodynamics.utils.MatrixUtils; * @author Joseph Lizier (email, * www) */ -public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureDiscreteInContextOfPastCalculator { +public class PredictiveInformationCalculatorDiscrete extends UnivariateMeasureDiscreteInContextOfPastCalculator { /** * User was formerly forced to create new instances through this factory method. @@ -116,7 +116,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD @Override public void initialise(int base, int blockLength) { - boolean baseOrHistoryChanged = (this.base != base) || (k != blockLength); + boolean baseOrHistoryChanged = (this.alphabetSize != base) || (k != blockLength); super.initialise(base, blockLength); if (baseOrHistoryChanged || (nextPastCount == null)) { @@ -142,7 +142,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD @Override public void initialise(){ - initialise(base, k); + initialise(alphabetSize, k); } /** @@ -165,9 +165,9 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD int prevVal = 0; int nextVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += timeSeries[p]; - nextVal *= base; + nextVal *= alphabetSize; nextVal += timeSeries[k-1+p]; } @@ -175,7 +175,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD for (int t = k; t < timeSteps - (k-1); t++) { // Update the next value: nextVal -= maxShiftedValue[timeSeries[t-1]]; - nextVal *= base; + nextVal *= alphabetSize; nextVal += timeSeries[k-1+t]; // Update the counts nextPastCount[nextVal][prevVal]++; @@ -183,7 +183,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD nextCount[nextVal]++; // Update the previous value: prevVal -= maxShiftedValue[timeSeries[t-k]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += timeSeries[t]; } } @@ -213,9 +213,9 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD prevVal[c] = 0; nextVal[c] = 0; for (int p = 0; p < k; p++) { - prevVal[c] *= base; + prevVal[c] *= alphabetSize; prevVal[c] += states[p][c]; - nextVal[c] *= base; + nextVal[c] *= alphabetSize; nextVal[c] += states[k-1+p][c]; } } @@ -225,7 +225,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD for (int c = 0; c < columns; c++) { // Update the next value: nextVal[c] -= maxShiftedValue[states[r-1][c]]; - nextVal[c] *= base; + nextVal[c] *= alphabetSize; nextVal[c] += states[k-1+r][c]; // Update the counts nextPastCount[nextVal[c]][prevVal[c]]++; @@ -233,7 +233,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD nextCount[nextVal[c]]++; // Update the previous value: prevVal[c] -= maxShiftedValue[states[r-k][c]]; - prevVal[c] *= base; + prevVal[c] *= alphabetSize; prevVal[c] += states[r][c]; } } @@ -270,9 +270,9 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD prevVal[r][c] = 0; nextVal[r][c] = 0; for (int p = 0; p < k; p++) { - prevVal[r][c] *= base; + prevVal[r][c] *= alphabetSize; prevVal[r][c] += states[p][r][c]; - nextVal[r][c] *= base; + nextVal[r][c] *= alphabetSize; nextVal[r][c] += states[k-1+p][r][c]; } } @@ -284,7 +284,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD for (int c = 0; c < agentColumns; c++) { // Update the next value: nextVal[r][c] -= maxShiftedValue[states[t-1][r][c]]; - nextVal[r][c] *= base; + nextVal[r][c] *= alphabetSize; nextVal[r][c] += states[k-1+t][r][c]; // Update the counts nextPastCount[nextVal[r][c]][prevVal[r][c]]++; @@ -292,7 +292,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD nextCount[nextVal[r][c]]++; // Update the previous value: prevVal[r][c] -= maxShiftedValue[states[t-k][r][c]]; - prevVal[r][c] *= base; + prevVal[r][c] *= alphabetSize; prevVal[r][c] += states[t][r][c]; } } @@ -321,9 +321,9 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD int prevVal = 0; int nextVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[p][col]; - nextVal *= base; + nextVal *= alphabetSize; nextVal += states[k-1+p][col]; } @@ -331,7 +331,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD for (int r = k; r < rows - (k-1); r++) { // Update the next value: nextVal -= maxShiftedValue[states[r-1][col]]; - nextVal *= base; + nextVal *= alphabetSize; nextVal += states[k-1+r][col]; // Add to the count for this particular transition: // (cell's assigned as above) @@ -340,7 +340,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD nextCount[nextVal]++; // Update the previous value: prevVal -= maxShiftedValue[states[r-k][col]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[r][col]; } } @@ -368,9 +368,9 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD int prevVal = 0; int nextVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[p][agentIndex1][agentIndex2]; - nextVal *= base; + nextVal *= alphabetSize; nextVal += states[k-1+p][agentIndex1][agentIndex2]; } @@ -378,7 +378,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD for (int t = k; t < timeSteps - (k-1); t++) { // Update the next value: nextVal -= maxShiftedValue[states[t-1][agentIndex1][agentIndex2]]; - nextVal *= base; + nextVal *= alphabetSize; nextVal += states[k-1+t][agentIndex1][agentIndex2]; // Add to the count for this particular transition: // (cell's assigned as above) @@ -387,7 +387,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD nextCount[nextVal]++; // Update the previous value: prevVal -= maxShiftedValue[states[t-k][agentIndex1][agentIndex2]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[t][agentIndex1][agentIndex2]; } } @@ -472,9 +472,9 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD int prevVal = 0; int nextVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += timeSeries[p]; - nextVal *= base; + nextVal *= alphabetSize; nextVal += timeSeries[k-1+p]; } @@ -482,7 +482,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD for (int t = k; t < timeSteps - (k-1); t++) { // Update the next value: nextVal -= maxShiftedValue[timeSeries[t-1]]; - nextVal *= base; + nextVal *= alphabetSize; nextVal += timeSeries[k-1+t]; logTerm = ( (double) nextPastCount[nextVal][prevVal] ) / ( (double) nextCount[nextVal] * @@ -501,7 +501,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD } // Update the previous value: prevVal -= maxShiftedValue[timeSeries[t-k]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += timeSeries[t]; } average = average/(double) (timeSteps - k - (k-1)); @@ -543,9 +543,9 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD prevVal[c] = 0; nextVal[c] = 0; for (int p = 0; p < k; p++) { - prevVal[c] *= base; + prevVal[c] *= alphabetSize; prevVal[c] += timeSeries[p][c]; - nextVal[c] *= base; + nextVal[c] *= alphabetSize; nextVal[c] += timeSeries[k-1+p][c]; } } @@ -554,7 +554,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD for (int c = 0; c < columns; c++) { // Update the next value: nextVal[c] -= maxShiftedValue[timeSeries[r-1][c]]; - nextVal[c] *= base; + nextVal[c] *= alphabetSize; nextVal[c] += timeSeries[k-1+r][c]; logTerm = ( (double) nextPastCount[nextVal[c]][prevVal[c]] ) / ( (double) nextCount[nextVal[c]] * @@ -573,7 +573,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD } // Update the previous value: prevVal[c] -= maxShiftedValue[timeSeries[r-k][c]]; - prevVal[c] *= base; + prevVal[c] *= alphabetSize; prevVal[c] += timeSeries[r][c]; } } @@ -618,9 +618,9 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD prevVal[r][c] = 0; nextVal[r][c] = 0; for (int p = 0; p < k; p++) { - prevVal[r][c] *= base; + prevVal[r][c] *= alphabetSize; prevVal[r][c] += timeSeries[p][r][c]; - nextVal[r][c] *= base; + nextVal[r][c] *= alphabetSize; nextVal[r][c] += timeSeries[k-1+p][r][c]; } } @@ -631,7 +631,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD for (int c = 0; c < agentColumns; c++) { // Update the next value: nextVal[r][c] -= maxShiftedValue[timeSeries[t-1][r][c]]; - nextVal[r][c] *= base; + nextVal[r][c] *= alphabetSize; nextVal[r][c] += timeSeries[k-1+t][r][c]; logTerm = ( (double) nextPastCount[nextVal[r][c]][prevVal[r][c]] ) / ( (double) nextCount[nextVal[r][c]] * @@ -650,7 +650,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD } // Update the previous value: prevVal[r][c] -= maxShiftedValue[timeSeries[t-k][r][c]]; - prevVal[r][c] *= base; + prevVal[r][c] *= alphabetSize; prevVal[r][c] += timeSeries[t][r][c]; } } @@ -690,16 +690,16 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD int prevVal = 0; int nextVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[p][col]; - nextVal *= base; + nextVal *= alphabetSize; 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 *= base; + nextVal *= alphabetSize; nextVal += states[k-1+r][col]; logTerm = ( (double) nextPastCount[nextVal][prevVal] ) / ( (double) nextCount[nextVal] * @@ -718,7 +718,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD } // Update the previous value: prevVal -= maxShiftedValue[states[r-k][col]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += states[r][col]; } average = average/(double) (rows - k - (k-1)); @@ -758,16 +758,16 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD int prevVal = 0; int nextVal = 0; for (int p = 0; p < k; p++) { - prevVal *= base; + prevVal *= alphabetSize; prevVal += timeSeries[p][agentIndex1][agentIndex2]; - nextVal *= base; + nextVal *= alphabetSize; 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 *= base; + nextVal *= alphabetSize; nextVal += timeSeries[k-1+t][agentIndex1][agentIndex2]; logTerm = ( (double) nextPastCount[nextVal][prevVal] ) / ( (double) nextCount[nextVal] * @@ -786,7 +786,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD } // Update the previous value: prevVal -= maxShiftedValue[timeSeries[t-k][agentIndex1][agentIndex2]]; - prevVal *= base; + prevVal *= alphabetSize; prevVal += timeSeries[t][agentIndex1][agentIndex2]; } average = average/(double) (timeSteps - k - (k-1)); @@ -844,7 +844,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD public int computePastValue(int[] x, int t) { int pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += x[t - k + 1 + p]; } return pastVal; @@ -863,7 +863,7 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD public int computePastValue(int[][] x, int i, int t) { int pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += x[t - k + 1 + p][i]; } return pastVal; @@ -883,9 +883,27 @@ public class PredictiveInformationCalculatorDiscrete extends SingleAgentMeasureD public int computePastValue(int[][][] x, int i, int j, int t) { int pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += x[t - k + 1 + p][i][j]; } return pastVal; } + + @Override + public void setObservations(Object[] observations) throws Exception { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'setObservations'"); + } + + @Override + public void startAddObservations() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'startAddObservations'"); + } + + @Override + public void finaliseAddObservations() throws Exception { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'finaliseAddObservations'"); + } } diff --git a/java/source/infodynamics/measures/discrete/SeparableInfoCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/SeparableInfoCalculatorDiscrete.java index 2593484..766cfe6 100755 --- a/java/source/infodynamics/measures/discrete/SeparableInfoCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/SeparableInfoCalculatorDiscrete.java @@ -255,7 +255,7 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula for (int c = 0; c < numAgents; c++) { pastVal[c] = 0; for (int p = 0; p < k; p++) { - pastVal[c] *= base; + pastVal[c] *= alphabetSize; pastVal[c] += states[p][c]; } } @@ -277,13 +277,13 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula sourceVal = states[t-1][(c-cleanedSourcesOffsets[sIndex]+numAgents) % numAgents]; sourceNumValueNextPastCount[sIndex][sourceVal][destVal][pastVal[c]]++; sourceNumValuePastCount[sIndex][sourceVal][pastVal[c]]++; - jointSourcesVal *= base; + jointSourcesVal *= alphabetSize; jointSourcesVal += sourceVal; } sourcesNextPastCount[jointSourcesVal][destVal][pastVal[c]]++; // Update the previous value: pastVal[c] -= maxShiftedValue[states[t-k][c]]; - pastVal[c] *= base; + pastVal[c] *= alphabetSize; pastVal[c] += states[t][c]; } } @@ -346,7 +346,7 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula for (int c = 0; c < agentColumns; c++) { pastVal[r][c] = 0; for (int p = 0; p < k; p++) { - pastVal[r][c] *= base; + pastVal[r][c] *= alphabetSize; pastVal[r][c] += states[p][r][c]; } } @@ -377,13 +377,13 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula [(c-cleanedSourcesOffsets[sIndex][COLUMN_INDEX]+agentColumns) % agentColumns]; sourceNumValueNextPastCount[sIndex][sourceVal][destVal][pastVal[r][c]]++; sourceNumValuePastCount[sIndex][sourceVal][pastVal[r][c]]++; - jointSourcesVal *= base; + jointSourcesVal *= alphabetSize; jointSourcesVal += sourceVal; } sourcesNextPastCount[jointSourcesVal][destVal][pastVal[r][c]]++; // Update the previous value: pastVal[r][c] -= maxShiftedValue[states[t-k][r][c]]; - pastVal[r][c] *= base; + pastVal[r][c] *= alphabetSize; pastVal[r][c] += states[t][r][c]; } } @@ -421,7 +421,7 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula // Initialise and store the current previous value for each column int pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += states[p][destCol]; } @@ -439,13 +439,13 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula sourceVal = states[r-1][cleanedSourcesAbsolute[sIndex]]; sourceNumValueNextPastCount[sIndex][sourceVal][destVal][pastVal]++; sourceNumValuePastCount[sIndex][sourceVal][pastVal]++; - jointSourcesVal *= base; + jointSourcesVal *= alphabetSize; jointSourcesVal += sourceVal; } sourcesNextPastCount[jointSourcesVal][destVal][pastVal]++; // Update the previous value: pastVal -= maxShiftedValue[states[r-k][destCol]]; - pastVal *= base; + pastVal *= alphabetSize; pastVal += states[r][destCol]; } } @@ -483,7 +483,7 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula // Initialise and store the current previous value for each column int pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += states[p][destAgentRow][destAgentColumn]; } @@ -502,13 +502,13 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula [cleanedSourcesAbsolute[sIndex][COLUMN_INDEX]]; sourceNumValueNextPastCount[sIndex][sourceVal][destVal][pastVal]++; sourceNumValuePastCount[sIndex][sourceVal][pastVal]++; - jointSourcesVal *= base; + jointSourcesVal *= alphabetSize; jointSourcesVal += sourceVal; } sourcesNextPastCount[jointSourcesVal][destVal][pastVal]++; // Update the previous value: pastVal -= maxShiftedValue[states[t-k][destAgentRow][destAgentColumn]]; - pastVal *= base; + pastVal *= alphabetSize; pastVal += states[t][destAgentRow][destAgentColumn]; } } @@ -560,7 +560,7 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula if (indexToModify < sourceValues.length) { // Assign values to our variables and make the recursive call - for (int s = 0; s < base; s++) { + for (int s = 0; s < alphabetSize; s++) { sourceValues[indexToModify] = s; computeAverageLocalOfObservations(sourceValues, indexToModify + 1); } @@ -575,7 +575,7 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula // Compute the joint source value first: jointSourcesVal = 0; for (int sIndex = 0; sIndex < numSources; sIndex++) { - jointSourcesVal *= base; + jointSourcesVal *= alphabetSize; jointSourcesVal += sourceValues[sIndex]; } @@ -584,7 +584,7 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula // contributions for each tuple. double[] localActAndTes = new double[numSources + 1]; for (int pastVal = 0; pastVal < base_power_k; pastVal++) { - for (int destVal = 0; destVal < base; destVal++) { + for (int destVal = 0; destVal < alphabetSize; destVal++) { if (sourcesNextPastCount[jointSourcesVal][destVal][pastVal] != 0) { // Add in the local active information storage first: logTerm = ( (double) nextPastCount[destVal][pastVal] ) / @@ -692,7 +692,7 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula for (int c = 0; c < numAgents; c++) { pastVal[c] = 0; for (int p = 0; p < k; p++) { - pastVal[c] *= base; + pastVal[c] *= alphabetSize; pastVal[c] += states[p][c]; } } @@ -751,7 +751,7 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula } // Update the previous value: pastVal[c] -= maxShiftedValue[states[t-k][c]]; - pastVal[c] *= base; + pastVal[c] *= alphabetSize; pastVal[c] += states[t][c]; } } @@ -838,7 +838,7 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula for (int c = 0; c < numAgentColumns; c++) { pastVal[r][c] = 0; for (int p = 0; p < k; p++) { - pastVal[r][c] *= base; + pastVal[r][c] *= alphabetSize; pastVal[r][c] += states[p][r][c]; } } @@ -906,7 +906,7 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula } // Update the previous value: pastVal[r][c] -= maxShiftedValue[states[t-k][r][c]]; - pastVal[r][c] *= base; + pastVal[r][c] *= alphabetSize; pastVal[r][c] += states[t][r][c]; } } @@ -983,7 +983,7 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula int pastVal = 0; pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += states[p][destCol]; } @@ -1038,7 +1038,7 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula } // Update the previous value: pastVal -= maxShiftedValue[states[r-k][destCol]]; - pastVal *= base; + pastVal *= alphabetSize; pastVal += states[r][destCol]; } @@ -1107,7 +1107,7 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula int pastVal = 0; pastVal = 0; for (int p = 0; p < k; p++) { - pastVal *= base; + pastVal *= alphabetSize; pastVal += states[p][destAgentRow][destAgentColumn]; } @@ -1163,7 +1163,7 @@ public class SeparableInfoCalculatorDiscrete extends ContextOfPastMeasureCalcula } // Update the previous value: pastVal -= maxShiftedValue[states[t-k][destAgentRow][destAgentColumn]]; - pastVal *= base; + pastVal *= alphabetSize; pastVal += states[t][destAgentRow][destAgentColumn]; } diff --git a/java/source/infodynamics/measures/discrete/SeparableInfoCalculatorDiscreteByAddition.java b/java/source/infodynamics/measures/discrete/SeparableInfoCalculatorDiscreteByAddition.java index 2579b2a..37f1677 100755 --- a/java/source/infodynamics/measures/discrete/SeparableInfoCalculatorDiscreteByAddition.java +++ b/java/source/infodynamics/measures/discrete/SeparableInfoCalculatorDiscreteByAddition.java @@ -66,7 +66,7 @@ public class SeparableInfoCalculatorDiscreteByAddition extends SeparableInfoCalc private void createAppTeCalculators() { ateCalcs = new TransferEntropyCalculatorDiscrete[numSources]; for (int i = 0; i < numSources; i++) { - ateCalcs[i] = TransferEntropyCalculatorDiscrete.newInstance(base, k); + ateCalcs[i] = TransferEntropyCalculatorDiscrete.newInstance(alphabetSize, k); ateCalcs[i].setPeriodicBoundaryConditions(periodicBoundaryConditions); } } @@ -276,7 +276,7 @@ public class SeparableInfoCalculatorDiscreteByAddition extends SeparableInfoCalc } int[] cleanedOffsets = cleanOffsetOfDestFromSources(offsetOfDestFromSources); TransferEntropyCalculatorDiscrete ateCalc = - TransferEntropyCalculatorDiscrete.newInstance(base, k); + TransferEntropyCalculatorDiscrete.newInstance(alphabetSize, k); ateCalc.setPeriodicBoundaryConditions(periodicBoundaryConditions); double[][] temp; for (int i = 0; i < numSources; i++) { @@ -312,7 +312,7 @@ public class SeparableInfoCalculatorDiscreteByAddition extends SeparableInfoCalc } int[][] cleanedOffsets = cleanOffsetOfDestFromSources(offsetOfDestFromSources); TransferEntropyCalculatorDiscrete ateCalc = - TransferEntropyCalculatorDiscrete.newInstance(base, k); + TransferEntropyCalculatorDiscrete.newInstance(alphabetSize, k); ateCalc.setPeriodicBoundaryConditions(periodicBoundaryConditions); double[][][] temp; for (int i = 0; i < numSources; i++) { @@ -346,7 +346,7 @@ public class SeparableInfoCalculatorDiscreteByAddition extends SeparableInfoCalc average = aiCalc.computeAverageLocal(states); int[] cleanedOffsets = cleanOffsetOfDestFromSources(sourceOffsets); TransferEntropyCalculatorDiscrete ateCalc = - TransferEntropyCalculatorDiscrete.newInstance(base, k); + TransferEntropyCalculatorDiscrete.newInstance(alphabetSize, k); ateCalc.setPeriodicBoundaryConditions(periodicBoundaryConditions); for (int i = 0; i < numSources; i++) { average += ateCalc.computeAverageLocal(states, cleanedOffsets[i]); @@ -363,7 +363,7 @@ public class SeparableInfoCalculatorDiscreteByAddition extends SeparableInfoCalc average = aiCalc.computeAverageLocal(states); int[][] cleanedOffsets = cleanOffsetOfDestFromSources(sourceOffsets); TransferEntropyCalculatorDiscrete ateCalc = - TransferEntropyCalculatorDiscrete.newInstance(base, k); + TransferEntropyCalculatorDiscrete.newInstance(alphabetSize, k); ateCalc.setPeriodicBoundaryConditions(periodicBoundaryConditions); for (int i = 0; i < numSources; i++) { average += ateCalc.computeAverageLocal(states, @@ -385,7 +385,7 @@ public class SeparableInfoCalculatorDiscreteByAddition extends SeparableInfoCalc } int[] cleanedOffsets = cleanAbsoluteSources(sourcesAbsolute, destCol); TransferEntropyCalculatorDiscrete ateCalc = - TransferEntropyCalculatorDiscrete.newInstance(base, k); + TransferEntropyCalculatorDiscrete.newInstance(alphabetSize, k); ateCalc.setPeriodicBoundaryConditions(periodicBoundaryConditions); double[] temp; for (int i = 0; i < numSources; i++) { @@ -421,7 +421,7 @@ public class SeparableInfoCalculatorDiscreteByAddition extends SeparableInfoCalc } int[][] cleanedSourcesAbsolute = cleanAbsoluteSources(sourcesAbsolute, destAgentRow, destAgentColumn); TransferEntropyCalculatorDiscrete ateCalc = - TransferEntropyCalculatorDiscrete.newInstance(base, k); + TransferEntropyCalculatorDiscrete.newInstance(alphabetSize, k); ateCalc.setPeriodicBoundaryConditions(periodicBoundaryConditions); double[] temp; for (int i = 0; i < numSources; i++) { @@ -454,7 +454,7 @@ public class SeparableInfoCalculatorDiscreteByAddition extends SeparableInfoCalc average = aiCalc.computeAverageLocal(states, destCol); int[] cleanedSourcesAbsolute = cleanAbsoluteSources(sourcesAbsolute, destCol); TransferEntropyCalculatorDiscrete ateCalc = - TransferEntropyCalculatorDiscrete.newInstance(base, k); + TransferEntropyCalculatorDiscrete.newInstance(alphabetSize, k); ateCalc.setPeriodicBoundaryConditions(periodicBoundaryConditions); for (int i = 0; i < numSources; i++) { average += ateCalc.computeAverageLocal(states, cleanedSourcesAbsolute[i], destCol); @@ -472,7 +472,7 @@ public class SeparableInfoCalculatorDiscreteByAddition extends SeparableInfoCalc average = aiCalc.computeAverageLocal(states); int[][] cleanedSourcesAbsolute = cleanAbsoluteSources(sourcesAbsolute, destAgentRow, destAgentColumn); TransferEntropyCalculatorDiscrete ateCalc = - TransferEntropyCalculatorDiscrete.newInstance(base, k); + TransferEntropyCalculatorDiscrete.newInstance(alphabetSize, k); ateCalc.setPeriodicBoundaryConditions(periodicBoundaryConditions); for (int i = 0; i < numSources; i++) { average += ateCalc.computeAverageLocal(states, diff --git a/java/source/infodynamics/measures/discrete/SingleAgentMeasureDiscrete.java b/java/source/infodynamics/measures/discrete/SingleAgentMeasureDiscrete.java deleted file mode 100755 index 507e7f6..0000000 --- a/java/source/infodynamics/measures/discrete/SingleAgentMeasureDiscrete.java +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Java Information Dynamics Toolkit (JIDT) - * Copyright (C) 2012, Joseph T. Lizier - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package infodynamics.measures.discrete; - -/** - * Interface for calculators of information-theoretic measures - * for single variables (e.g. entropy, active information storage). - * The interface defines common operations such as - * adding observations and calculating - * local and average values, etc. - * - *

Usage is as per {@link InfoMeasureCalculatorDiscrete}, with - * many methods for supplying observations and making - * calculations defined here.

- * - *

It would ideally be an abstract class to be inherited from, but - * it's more important for some of our calculators to have inheritance from - * ContextOfPastCalculator, and since java doesn't allow multiple - * inheritance, one of them has to miss out. - * To get around this, we combine the two in - * {@link SingleAgentMeasureDiscreteInContextOfPastCalculator}. - *

- * - * @author Joseph Lizier (email, - * www) - */ -public interface SingleAgentMeasureDiscrete { - - /** - * Property name for definite alphabet size. Attempting - * to use observations beyond this property will throw - * errors. - */ - public static final String ALPHABET_SIZE = "ALPHABET_SIZE"; - - /** - * Property name for determining when to switch to HashTable - * memory management system. (default is TODO...) - */ - public static final String MAX_ALPHA_SIZE_TO_STORE = "MAX_ALPHA_SIZE_TO_STORE"; - - /** - * Property name for whether or not the calculator is using - * the HashTable memory management. - * - * TODO -- maybe this shouldn't be a property... it should def be - * mutually exclusive with alphaSize. - */ - public static final String KNOWN_INTEGER_RANGE = "KNOWN_INTEGER_RANGE"; - - - /** - * Property name for determining whether or not the calculator - * is still adding observations. - * - * TODO -- I think this is the nicest way to do this, though I'd rather a private - * boolean not set by setProperties. This probs shouldn't be a property at all... - */ - public static final String EXPECTING_OBSERVATIONS = "EXPECTING_OBSERVATIONS"; - - /** - * Initialise the calculator with same or unknown alphabet size - */ - public void initialise(); - - /** - * Sets the samples from which to compute the PDF for the entropy. - * Should only be called once, the last call contains the - * observations that are used (they are not accumulated). - * - * @param observations array of (univariate) samples - * @throws Exception - */ - public void setObservations(Object[] observations) throws Exception; - - /** - * Signal that we will add in the samples for computing the PDF - * from several disjoint time-series or trials via calls to - * "addObservations" rather than "setObservations" type methods - * (defined by the child interfaces and classes). - */ - public void startAddObservations(); - - /** - * Signal that the observations are now all added, PDFs can now be constructed. - * - * @throws Exception when the estimator has no observations. - */ - public void finaliseAddObservations() throws Exception; - - /** - * Add observations in to our estimates of the pdfs. - * - * @param states series of samples - */ - public void addObservations(Object states[]); - - - /** - * Compute the average value of the measure - * from the previously-supplied samples. - * - * Must set average, min and max - * - * @return the estimate of the measure - */ - public double computeAverageLocalOfObservations(); - - /** - * Computes local information theoretic measure for the given - * states, using pdfs built up from observations previously - * sent in via the addObservations method. - * - * Must set average, min and max - * - * @param states time series of samples - * @return time-series of local values (indexed as per states) - */ - public double[] computeLocalFromPreviousObservations(int states[]); - - /** - * Computes local information theoretic measure for the given - * states, using pdfs built up from observations previously - * sent in via the addObservations method. - * This method to be used for homogeneous agents only, - * since the local values will be computed for all variables. - * - * Must set average, min and max - * - * @param states multivariate time series - * (1st index is time, 2nd index is variable number) - * @return 2D time-series of local values (indexed as per states) - */ - public double[][] computeLocalFromPreviousObservations(int states[][]); - - /** - * Computes local information theoretic measure for the given - * variable in the 2D time-series - * states, using pdfs built up from observations previously - * sent in via the addObservations method. - * This method is suitable for heterogeneous agents, since - * the specific variable is identified. - * - * Must set average, min and max. - * - * @param states multivariate time series - * (1st index is time, 2nd index is variable number) - * @param col index of the given variable - * @return time-series of local values for the variable - */ - public double[] computeLocalFromPreviousObservations(int states[][], int col); - - /** - * Computes local information theoretic measure for the given - * states, using pdfs built up from observations previously - * sent in via the addObservations method - * This method to be used for homogeneous agents only, - * since the local values will be computed for all variables. - * - * Must set average, min and max - * - * @param states multivariate time series - * (1st index is time, 2nd index is variable row number, - * 3rd is variable column number) - * @return 3D time-series of local values (indexed as per states) - */ - public double[][][] computeLocalFromPreviousObservations(int states[][][]); - - /** - * Computes the local information theoretic measure for the given - * variable in the 3D time-series - * states, using pdfs built up from observations previously - * sent in via the addObservations method - * This method is suitable for heterogeneous agents, since - * the specific variable is identified. - * - * Must set average, min and max - * - * @param states multivariate time series - * (1st index is time, 2nd index is variable row number, - * 3rd is variable column number) - * @param index1 row index of the given variable - * @param index2 column index of the given variable - * @return time-series of local values for the variable - */ - public double[] computeLocalFromPreviousObservations(int states[][][], int index1, int index2); - - /** - * Standalone routine to - * compute the local information-theoretic measure across a - * time-series of states. - * Return a time-series array of local values. - * First history rows are zeros when the measure must build up - * embedded history of the variable. - * - * @param states time series of samples - * @return time-series of local values (indexed as per states) - */ - public double[] computeLocal(int states[]); - - /** - * Standalone routine to - * compute the local information-theoretic measure across a 2D spatiotemporal - * array of the states of homogeneous agents, - * Return a 2D spatiotemporal array of local values. - * First history rows are zeros when the measure must build up - * embedded history of the variable. - * - * @param states multivariate time series - * (1st index is time, 2nd index is variable number) - * @return 2D time-series of local values (indexed as per states) - */ - public double[][] computeLocal(int states[][]); - - /** - * Standalone routine to - * compute the local information theoretic measure across a 3D spatiotemporal - * array of the states of homogeneous agents - * Return a 3D spatiotemporal array of local values. - * First history rows are zeros when the measure must build up - * embedded history of the variable. - * - * @param states multivariate time series - * (1st index is time, 2nd index is variable row number, - * 3rd is variable column number) - * @return 3D time-series of local values (indexed as per states) - */ - public double[][][] computeLocal(int states[][][]); - - /** - * Standalone routine to - * compute the average information theoretic measure across a time-series - * of states. - * Return the average. - * - * @param states time series of samples - * @return average of the information-theoretic measure. - * @throws Exception if states parameter is empty. - */ - public double computeAverageLocal(int states[]) throws Exception; - - /** - * Standalone routine to - * compute the average information theoretic measure across a 2D spatiotemporal - * array of the states of homogeneous agents. - * Return the average. - * This method to be called for homogeneous agents only, - * since all variables are used in the PDFs. - * - * @param states multivariate time series - * (1st index is time, 2nd index is variable number) - * @return average of the information-theoretic measure. - */ - public double computeAverageLocal(int states[][]); - - /** - * Standalone routine to - * compute the average information theoretic measure across a 3D spatiotemporal - * array of the states of homogeneous agents. - * Return the average. - * This method to be called for homogeneous agents only, - * since all variables are used in the PDFs. - * - * @param states multivariate time series - * (1st index is time, 2nd index is variable row number, - * 3rd is variable column number) - * @return average of the information-theoretic measure. - */ - public double computeAverageLocal(int states[][][]); - - /** - * Standalone routine to - * compute local information theoretic measure for one variable - * in a 2D spatiotemporal - * multivariate array. - * Return a time-series array of local values. - * First history rows are zeros when the measure must build up - * embedded history of the variable. - * This method should be used for heterogeneous agents - * - * @param states multivariate time series - * (1st index is time, 2nd index is variable number) - * @param col index of the given variable - * @return time-series of local values of the measure for - * the given variable - */ - public double[] computeLocal(int states[][], int col); - - /** - * Standalone routine to - * compute local information theoretic measure for one variable - * in a 3D spatiotemporal - * multivariate array. - * Return a time-series array of local values. - * First history rows are zeros when the measure must build up - * embedded history of the variable. - * This method should be used for heterogeneous agents - * - * @param states multivariate time series - * (1st index is time, 2nd index is variable row number, - * 3rd is variable column number) - * @param index1 row index of the given variable - * @param index2 column index of the given variable - * @return time-series of local values of the measure for - * the given variable - */ - public double[] computeLocal(int states[][][], int index1, int index2); - - /** - * Standalone routine to - * compute the average information theoretic measure - * for a single agent in a multivariate time series. - * Returns the average. - * This method suitable for heterogeneous agents. - * - * @param states multivariate time series - * (1st index is time, 2nd index is variable number) - * @param col index of the given variable - * @return average of the measure for the given variable. - */ - public double computeAverageLocal(int states[][], int col); - - /** - * Standalone routine to - * compute the average information theoretic measure - * for a single agent in a multivariate time series. - * Returns the average. - * This method suitable for heterogeneous agents. - * - * @param states multivariate time series - * (1st index is time, 2nd index is variable row number, - * 3rd is variable column number) - * @param index1 row index of the given variable - * @param index2 column index of the given variable - * @return average of the measure for the given variable. - */ - public double computeAverageLocal(int states[][][], int index1, int index2); - - /** - * Add observations in to our estimates of the pdfs. - * This call suitable only for homogeneous agents, as all - * agents will contribute to the PDFs. - * - * @param states multivariate time series - * (1st index is time, 2nd index is variable number) - */ - @Deprecated - public void addObservations(int states[][]); - - /** - * Add observations for a single variable of the multi-agent system - * to our estimates of the pdfs. - * This call should be made as opposed to {@link #addObservations(int[][])} - * for computing active info for heterogeneous agents. - * - * @deprecated - * @param states multivariate time series - * (1st index is time, 2nd index is variable number) - * @param col index of agent - */ - @Deprecated - public void addObservations(int states[][], int col); - - /** - * Add observations in to our estimates of the pdfs. - * This call suitable only for homogeneous agents, as all - * agents will contribute to single pdfs. - * - * @deprecated - * @param states multivariate time series - * (1st index is time, 2nd index is variable row number, - * 3rd is variable column number) - */ - @Deprecated - public void addObservations(int states[][][]); - - /** - * Add observations for a single agent of the multi-agent system - * to our estimates of the pdfs. - * This call should be made as opposed to {@link #addObservations(int[][][])} - * for computing active info for heterogeneous agents. - * - * @deprecated - * @param states multivariate time series - * (1st index is time, 2nd index is variable row number, - * 3rd is variable column number) - * @param index1 row index index the variable - * @param index2 column index of the variable - */ - @Deprecated - public void addObservations(int states[][][], int index1, int index2); - - /** - * Initialise the calculator with (potentially) a new alphabet size - * - * TODO - I don't think so anymore... this should be done with set property - * Deprecated, use initialise() and setProperty("ALPHABET_SIZE", "n") instead. - * @deprecated - * @param alphabetSize - */ - @Deprecated - public void initialise(int alphabetSize); -} diff --git a/java/source/infodynamics/measures/discrete/TransferEntropyCalculatorDiscrete.java b/java/source/infodynamics/measures/discrete/TransferEntropyCalculatorDiscrete.java index a178b1a..93fa00e 100755 --- a/java/source/infodynamics/measures/discrete/TransferEntropyCalculatorDiscrete.java +++ b/java/source/infodynamics/measures/discrete/TransferEntropyCalculatorDiscrete.java @@ -294,7 +294,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu public void initialise(int base, int destHistoryEmbedLength, int destEmbeddingDelay, int sourceHistoryEmbeddingLength, int sourceEmbeddingDelay, int delay) { - boolean paramsChanged = (this.base != base) || (k != destHistoryEmbedLength) || + boolean paramsChanged = (this.alphabetSize != base) || (k != destHistoryEmbedLength) || (this.destEmbeddingDelay != destEmbeddingDelay) || (this.sourceHistoryEmbedLength != sourceHistoryEmbeddingLength) || (this.sourceEmbeddingDelay != sourceEmbeddingDelay) || (this.delay != delay); super.initialise(base, destHistoryEmbedLength); @@ -324,7 +324,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu @Override public void initialise(){ - initialise(base, k, destEmbeddingDelay, sourceHistoryEmbedLength, + initialise(this.alphabetSize, k, destEmbeddingDelay, sourceHistoryEmbedLength, sourceEmbeddingDelay, delay); } @@ -374,7 +374,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu pastVal[d] += dest[startTime + startObservationTime + d - 1 - (k-1)*destEmbeddingDelay + p*destEmbeddingDelay]; - pastVal[d] *= base; + pastVal[d] *= this.alphabetSize; } } // Next for the source: @@ -389,7 +389,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu sourcePastVal[d] += source[startTime + startObservationTime + d - delay - (sourceHistoryEmbedLength-1)*sourceEmbeddingDelay + p*sourceEmbeddingDelay]; - sourcePastVal[d] *= base; + sourcePastVal[d] *= this.alphabetSize; } } @@ -416,12 +416,12 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu // for this phase we back out the oldest value which we'll no longer need: if (k > 0) { pastVal[destEmbeddingPhase] -= maxShiftedValue[dest[r-1-(k-1)*destEmbeddingDelay]]; - pastVal[destEmbeddingPhase] *= base; // and shift the others up + pastVal[destEmbeddingPhase] *= this.alphabetSize; // and shift the others up } sourcePastVal[sourceEmbeddingPhase] -= maxShiftedSourceValue[ source[r-delay-(sourceHistoryEmbedLength-1)*sourceEmbeddingDelay]]; - sourcePastVal[sourceEmbeddingPhase] *= base; // and shift the others up + sourcePastVal[sourceEmbeddingPhase] *= this.alphabetSize; // and shift the others up // then update the phase destEmbeddingPhase = (destEmbeddingPhase + 1) % destEmbeddingDelay; sourceEmbeddingPhase = (sourceEmbeddingPhase + 1) % sourceEmbeddingDelay; @@ -463,7 +463,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu pastVal[d] += dest[startObservationTime + d - 1 - (k-1)*destEmbeddingDelay + p*destEmbeddingDelay]; - pastVal[d] *= base; + pastVal[d] *= this.alphabetSize; } } // We can take an observation if timeSinceLastDestInvalid >= minDestLengthRequired @@ -489,7 +489,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu sourcePastVal[d] += source[startObservationTime + d - delay - (sourceHistoryEmbedLength-1)*sourceEmbeddingDelay + p*sourceEmbeddingDelay]; - sourcePastVal[d] *= base; + sourcePastVal[d] *= this.alphabetSize; } } // We can take an observation if timeSinceLastSourceInvalid >= minSourceLengthRequired @@ -551,12 +551,12 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu // for this phase we back out the oldest value which we'll no longer need: if (k > 0) { pastVal[destEmbeddingPhase] -= maxShiftedValue[dest[r-1-(k-1)*destEmbeddingDelay]]; - pastVal[destEmbeddingPhase] *= base; // and shift the others up + pastVal[destEmbeddingPhase] *= this.alphabetSize; // and shift the others up } sourcePastVal[sourceEmbeddingPhase] -= maxShiftedSourceValue[ source[r-delay-(sourceHistoryEmbedLength-1)*sourceEmbeddingDelay]]; - sourcePastVal[sourceEmbeddingPhase] *= base; // and shift the others up + sourcePastVal[sourceEmbeddingPhase] *= this.alphabetSize; // and shift the others up // then update the phase destEmbeddingPhase = (destEmbeddingPhase + 1) % destEmbeddingDelay; sourceEmbeddingPhase = (sourceEmbeddingPhase + 1) % sourceEmbeddingDelay; @@ -606,7 +606,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu pastVal[c][d] += states[startObservationTime + d - 1 - (k-1)*destEmbeddingDelay + p*destEmbeddingDelay][c]; - pastVal[c][d] *= base; + pastVal[c][d] *= this.alphabetSize; } } } @@ -633,7 +633,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu sourcePastVal[c][d] += states[startObservationTime + d - delay - (sourceHistoryEmbedLength-1)*sourceEmbeddingDelay + p*sourceEmbeddingDelay][sourceVariable]; - sourcePastVal[c][d] *= base; + sourcePastVal[c][d] *= this.alphabetSize; } } } @@ -674,12 +674,12 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu // for this phase we back out the oldest value which we'll no longer need: if (k > 0) { pastVal[c][destEmbeddingPhase] -= maxShiftedValue[states[r-1-(k-1)*destEmbeddingDelay][c]]; - pastVal[c][destEmbeddingPhase] *= base; // and shift the others up + pastVal[c][destEmbeddingPhase] *= this.alphabetSize; // and shift the others up } sourcePastVal[c][sourceEmbeddingPhase] -= maxShiftedSourceValue[ states[r-delay-(sourceHistoryEmbedLength-1)*sourceEmbeddingDelay][sourceVariable]]; - sourcePastVal[c][sourceEmbeddingPhase] *= base; // and shift the others up + sourcePastVal[c][sourceEmbeddingPhase] *= this.alphabetSize; // and shift the others up } // then update the phase destEmbeddingPhase = (destEmbeddingPhase + 1) % destEmbeddingDelay; @@ -737,7 +737,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu pastVal[r][c][d] += states[startObservationTime + d - 1 - (k-1)*destEmbeddingDelay + p*destEmbeddingDelay][r][c]; - pastVal[r][c][d] *= base; + pastVal[r][c][d] *= this.alphabetSize; } } } @@ -777,7 +777,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu sourcePastVal[r][c][d] += states[startObservationTime + d - delay - (sourceHistoryEmbedLength-1)*sourceEmbeddingDelay + p*sourceEmbeddingDelay][sourceAgentRow][sourceAgentColumn]; - sourcePastVal[r][c][d] *= base; + sourcePastVal[r][c][d] *= this.alphabetSize; } } } @@ -830,12 +830,12 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu // for this phase we back out the oldest value which we'll no longer need: if (k > 0) { pastVal[r][c][destEmbeddingPhase] -= maxShiftedValue[states[t-1-(k-1)*destEmbeddingDelay][r][c]]; - pastVal[r][c][destEmbeddingPhase] *= base; // and shift the others up + pastVal[r][c][destEmbeddingPhase] *= this.alphabetSize; // and shift the others up } sourcePastVal[r][c][sourceEmbeddingPhase] -= maxShiftedSourceValue[ states[t-delay-(sourceHistoryEmbedLength-1)*sourceEmbeddingDelay][sourceAgentRow][sourceAgentColumn]]; - sourcePastVal[r][c][sourceEmbeddingPhase] *= base; // and shift the others up + sourcePastVal[r][c][sourceEmbeddingPhase] *= this.alphabetSize; // and shift the others up } } // then update the phase @@ -879,7 +879,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu pastVal[d] += states[startObservationTime + d - 1 - (k-1)*destEmbeddingDelay + p*destEmbeddingDelay][destIndex]; - pastVal[d] *= base; + pastVal[d] *= this.alphabetSize; } } // Next for the source: @@ -894,7 +894,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu sourcePastVal[d] += states[startObservationTime + d - delay - (sourceHistoryEmbedLength-1)*sourceEmbeddingDelay + p*sourceEmbeddingDelay][sourceIndex]; - sourcePastVal[d] *= base; + sourcePastVal[d] *= this.alphabetSize; } } @@ -921,12 +921,12 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu // for this phase we back out the oldest value which we'll no longer need: if (k > 0) { pastVal[destEmbeddingPhase] -= maxShiftedValue[states[r-1-(k-1)*destEmbeddingDelay][destIndex]]; - pastVal[destEmbeddingPhase] *= base; // and shift the others up + pastVal[destEmbeddingPhase] *= this.alphabetSize; // and shift the others up } sourcePastVal[sourceEmbeddingPhase] -= maxShiftedSourceValue[ states[r-delay-(sourceHistoryEmbedLength-1)*sourceEmbeddingDelay][sourceIndex]]; - sourcePastVal[sourceEmbeddingPhase] *= base; // and shift the others up + sourcePastVal[sourceEmbeddingPhase] *= this.alphabetSize; // and shift the others up // then update the phase destEmbeddingPhase = (destEmbeddingPhase + 1) % destEmbeddingDelay; sourceEmbeddingPhase = (sourceEmbeddingPhase + 1) % sourceEmbeddingDelay; @@ -972,7 +972,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu pastVal[d] += states[startObservationTime + d - 1 - (k-1)*destEmbeddingDelay + p*destEmbeddingDelay][destRowIndex][destColumnIndex]; - pastVal[d] *= base; + pastVal[d] *= this.alphabetSize; } } // Next for the source: @@ -987,7 +987,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu sourcePastVal[d] += states[startObservationTime + d - delay - (sourceHistoryEmbedLength-1)*sourceEmbeddingDelay + p*sourceEmbeddingDelay][sourceRowIndex][sourceColumnIndex]; - sourcePastVal[d] *= base; + sourcePastVal[d] *= this.alphabetSize; } } @@ -1014,12 +1014,12 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu // for this phase we back out the oldest value which we'll no longer need: if (k > 0) { pastVal[destEmbeddingPhase] -= maxShiftedValue[states[r-1-(k-1)*destEmbeddingDelay][destRowIndex][destColumnIndex]]; - pastVal[destEmbeddingPhase] *= base; // and shift the others up + pastVal[destEmbeddingPhase] *= this.alphabetSize; // and shift the others up } sourcePastVal[sourceEmbeddingPhase] -= maxShiftedSourceValue[ states[r-delay-(sourceHistoryEmbedLength-1)*sourceEmbeddingDelay][sourceRowIndex][sourceColumnIndex]]; - sourcePastVal[sourceEmbeddingPhase] *= base; // and shift the others up + sourcePastVal[sourceEmbeddingPhase] *= this.alphabetSize; // and shift the others up // then update the phase destEmbeddingPhase = (destEmbeddingPhase + 1) % destEmbeddingDelay; sourceEmbeddingPhase = (sourceEmbeddingPhase + 1) % sourceEmbeddingDelay; @@ -1171,7 +1171,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu if (pastCount[pastVal] == 0) { continue; } - for (int destVal = 0; destVal < base; destVal++) { + for (int destVal = 0; destVal < this.alphabetSize; destVal++) { // compute p(dest,past) // double p_dest_past = (double) destPastCount[destVal][pastVal] / (double) observations; if (nextPastCount[destVal][pastVal] == 0) { @@ -1234,7 +1234,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu double active = 0.0; double activeCont = 0.0; - for (int nextVal = 0; nextVal < base; nextVal++) { + for (int nextVal = 0; nextVal < this.alphabetSize; nextVal++) { // compute p_next double p_next = (double) nextCount[nextVal] / (double) observations; for (int prevVal = 0; prevVal < base_power_k; prevVal++) { @@ -1263,7 +1263,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu System.out.println("Src\tDst\tPast\tc(s,d,p)\tc(s,p)\tc(d,p)\tc(p)"); for (int pastVal = 0; pastVal < base_power_k; pastVal++) { - for (int destVal = 0; destVal < base; destVal++) { + for (int destVal = 0; destVal < this.alphabetSize; destVal++) { for (int sourceVal = 0; sourceVal < base_power_l; sourceVal++) { // Compute TE contribution: System.out.println(sourceVal + "\t" + destVal + "\t" + pastVal + "\t" + @@ -1315,7 +1315,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu for (int pastVal = 0; pastVal < base_power_k; pastVal++) { MatrixUtils.fill(pastValues, pastVal, t_p, pastCount[pastVal]); t_p += pastCount[pastVal]; - for (int destVal = 0; destVal < base; destVal++) { + for (int destVal = 0; destVal < this.alphabetSize; destVal++) { MatrixUtils.fill(destValues, destVal, t_d, nextPastCount[destVal][pastVal]); t_d += nextPastCount[destVal][pastVal]; } @@ -1324,7 +1324,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu // If we want a calculator just like this one, we should provide all of // the same parameters: TransferEntropyCalculatorDiscrete ate2 = - new TransferEntropyCalculatorDiscrete(base, k, destEmbeddingDelay, + new TransferEntropyCalculatorDiscrete(this.alphabetSize, k, destEmbeddingDelay, sourceHistoryEmbedLength, sourceEmbeddingDelay, delay); ate2.initialise(); ate2.observations = observations; @@ -1366,7 +1366,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu } return new ChiSquareMeasurementDistribution(average, observations, - (base_power_l - 1)*(base - 1)*(base_power_k)); + (base_power_l - 1)*(this.alphabetSize - 1)*(base_power_k)); } /** @@ -1425,7 +1425,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu pastVal[d] += dest[startObservationTime + d - 1 - (k-1)*destEmbeddingDelay + p*destEmbeddingDelay]; - pastVal[d] *= base; + pastVal[d] *= this.alphabetSize; } } // Next for the source: @@ -1440,7 +1440,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu sourcePastVal[d] += source[startObservationTime + d - delay - (sourceHistoryEmbedLength-1)*sourceEmbeddingDelay + p*sourceEmbeddingDelay]; - sourcePastVal[d] *= base; + sourcePastVal[d] *= this.alphabetSize; } } @@ -1472,12 +1472,12 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu // for this phase we back out the oldest value which we'll no longer need: if (k > 0) { pastVal[destEmbeddingPhase] -= maxShiftedValue[dest[t-1-(k-1)*destEmbeddingDelay]]; - pastVal[destEmbeddingPhase] *= base; // and shift the others up + pastVal[destEmbeddingPhase] *= this.alphabetSize; // and shift the others up } sourcePastVal[sourceEmbeddingPhase] -= maxShiftedSourceValue[ source[t-delay-(sourceHistoryEmbedLength-1)*sourceEmbeddingDelay]]; - sourcePastVal[sourceEmbeddingPhase] *= base; // and shift the others up + sourcePastVal[sourceEmbeddingPhase] *= this.alphabetSize; // and shift the others up // then update the phase destEmbeddingPhase = (destEmbeddingPhase + 1) % destEmbeddingDelay; sourceEmbeddingPhase = (sourceEmbeddingPhase + 1) % sourceEmbeddingDelay; @@ -1537,7 +1537,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu pastVal[c][d] += states[startObservationTime + d - 1 - (k-1)*destEmbeddingDelay + p*destEmbeddingDelay][c]; - pastVal[c][d] *= base; + pastVal[c][d] *= this.alphabetSize; } } } @@ -1564,7 +1564,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu sourcePastVal[c][d] += states[startObservationTime + d - delay - (sourceHistoryEmbedLength-1)*sourceEmbeddingDelay + p*sourceEmbeddingDelay][sourceVariable]; - sourcePastVal[c][d] *= base; + sourcePastVal[c][d] *= this.alphabetSize; } } } @@ -1608,12 +1608,12 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu // for this phase we back out the oldest value which we'll no longer need: if (k > 0) { pastVal[c][destEmbeddingPhase] -= maxShiftedValue[states[t-1-(k-1)*destEmbeddingDelay][c]]; - pastVal[c][destEmbeddingPhase] *= base; // and shift the others up + pastVal[c][destEmbeddingPhase] *= this.alphabetSize; // and shift the others up } sourcePastVal[c][sourceEmbeddingPhase] -= maxShiftedSourceValue[ states[t-delay-(sourceHistoryEmbedLength-1)*sourceEmbeddingDelay][sourceVariable]]; - sourcePastVal[c][sourceEmbeddingPhase] *= base; // and shift the others up + sourcePastVal[c][sourceEmbeddingPhase] *= this.alphabetSize; // and shift the others up } // then update the phase destEmbeddingPhase = (destEmbeddingPhase + 1) % destEmbeddingDelay; @@ -1689,7 +1689,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu pastVal[r][c][d] += states[startObservationTime + d - 1 - (k-1)*destEmbeddingDelay + p*destEmbeddingDelay][r][c]; - pastVal[r][c][d] *= base; + pastVal[r][c][d] *= this.alphabetSize; } } } @@ -1729,7 +1729,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu sourcePastVal[r][c][d] += states[startObservationTime + d - delay - (sourceHistoryEmbedLength-1)*sourceEmbeddingDelay + p*sourceEmbeddingDelay][sourceAgentRow][sourceAgentColumn]; - sourcePastVal[r][c][d] *= base; + sourcePastVal[r][c][d] *= this.alphabetSize; } } } @@ -1787,12 +1787,12 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu // for this phase we back out the oldest value which we'll no longer need: if (k > 0) { pastVal[r][c][destEmbeddingPhase] -= maxShiftedValue[states[t-1-(k-1)*destEmbeddingDelay][r][c]]; - pastVal[r][c][destEmbeddingPhase] *= base; // and shift the others up + pastVal[r][c][destEmbeddingPhase] *= this.alphabetSize; // and shift the others up } sourcePastVal[r][c][sourceEmbeddingPhase] -= maxShiftedSourceValue[ states[t-delay-(sourceHistoryEmbedLength-1)*sourceEmbeddingDelay][sourceAgentRow][sourceAgentColumn]]; - sourcePastVal[r][c][sourceEmbeddingPhase] *= base; // and shift the others up + sourcePastVal[r][c][sourceEmbeddingPhase] *= this.alphabetSize; // and shift the others up } } // then update the phase @@ -1852,7 +1852,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu pastVal[d] += states[startObservationTime + d - 1 - (k-1)*destEmbeddingDelay + p*destEmbeddingDelay][destIndex]; - pastVal[d] *= base; + pastVal[d] *= this.alphabetSize; } } // Next for the source: @@ -1867,7 +1867,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu sourcePastVal[d] += states[startObservationTime + d - delay - (sourceHistoryEmbedLength-1)*sourceEmbeddingDelay + p*sourceEmbeddingDelay][sourceIndex]; - sourcePastVal[d] *= base; + sourcePastVal[d] *= this.alphabetSize; } } @@ -1899,12 +1899,12 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu // for this phase we back out the oldest value which we'll no longer need: if (k > 0) { pastVal[destEmbeddingPhase] -= maxShiftedValue[states[r-1-(k-1)*destEmbeddingDelay][destIndex]]; - pastVal[destEmbeddingPhase] *= base; // and shift the others up + pastVal[destEmbeddingPhase] *= this.alphabetSize; // and shift the others up } sourcePastVal[sourceEmbeddingPhase] -= maxShiftedSourceValue[ states[r-delay-(sourceHistoryEmbedLength-1)*sourceEmbeddingDelay][sourceIndex]]; - sourcePastVal[sourceEmbeddingPhase] *= base; // and shift the others up + sourcePastVal[sourceEmbeddingPhase] *= this.alphabetSize; // and shift the others up // then update the phase destEmbeddingPhase = (destEmbeddingPhase + 1) % destEmbeddingDelay; sourceEmbeddingPhase = (sourceEmbeddingPhase + 1) % sourceEmbeddingDelay; @@ -1958,7 +1958,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu pastVal[d] += states[startObservationTime + d - 1 - (k-1)*destEmbeddingDelay + p*destEmbeddingDelay][destRowIndex][destColumnIndex]; - pastVal[d] *= base; + pastVal[d] *= this.alphabetSize; } } // Next for the source: @@ -1973,7 +1973,7 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu sourcePastVal[d] += states[startObservationTime + d - delay - (sourceHistoryEmbedLength-1)*sourceEmbeddingDelay + p*sourceEmbeddingDelay][sourceRowIndex][sourceColumnIndex]; - sourcePastVal[d] *= base; + sourcePastVal[d] *= this.alphabetSize; } } @@ -2005,12 +2005,12 @@ public class TransferEntropyCalculatorDiscrete extends ContextOfPastMeasureCalcu // for this phase we back out the oldest value which we'll no longer need: if (k > 0) { pastVal[destEmbeddingPhase] -= maxShiftedValue[states[r-1-(k-1)*destEmbeddingDelay][destRowIndex][destColumnIndex]]; - pastVal[destEmbeddingPhase] *= base; // and shift the others up + pastVal[destEmbeddingPhase] *= this.alphabetSize; // and shift the others up } sourcePastVal[sourceEmbeddingPhase] -= maxShiftedSourceValue[ states[r-delay-(sourceHistoryEmbedLength-1)*sourceEmbeddingDelay][sourceRowIndex][sourceColumnIndex]]; - sourcePastVal[sourceEmbeddingPhase] *= base; // and shift the others up + sourcePastVal[sourceEmbeddingPhase] *= this.alphabetSize; // and shift the others up // then update the phase destEmbeddingPhase = (destEmbeddingPhase + 1) % destEmbeddingDelay; sourceEmbeddingPhase = (sourceEmbeddingPhase + 1) % sourceEmbeddingDelay; diff --git a/java/source/infodynamics/measures/discrete/UnivariateMeasureDiscrete.java b/java/source/infodynamics/measures/discrete/UnivariateMeasureDiscrete.java new file mode 100644 index 0000000..6023f94 --- /dev/null +++ b/java/source/infodynamics/measures/discrete/UnivariateMeasureDiscrete.java @@ -0,0 +1,150 @@ +/* + * Java Information Dynamics Toolkit (JIDT) + * Copyright (C) 2012, Joseph T. Lizier + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package infodynamics.measures.discrete; + +/** + * Interface for calculators of information-theoretic measures + * for single variables (e.g. entropy, active information storage). + * The interface defines common operations such as + * adding observations and calculating + * local and average values, etc. + * + *

Usage is as per {@link InfoMeasureCalculatorDiscrete}, with + * many methods for supplying observations and making + * calculations defined here.

+ * + *

It would ideally be an abstract class to be inherited from, but + * it's more important for some of our calculators to have inheritance from + * ContextOfPastCalculator, and since java doesn't allow multiple + * inheritance, one of them has to miss out. + * To get around this, we combine the two in + * {@link UnivariateMeasureDiscreteInContextOfPastCalculator}. + *

+ * + * @author Joseph Lizier (email, + * www) + */ +public interface UnivariateMeasureDiscrete { + + /** + * Property name for definite alphabet size. Attempting + * to use observations beyond this property will throw + * errors. + */ + public static final String ALPHABET_SIZE = "ALPHABET_SIZE"; + + /** + * Property name for if the alphabet size is known. + */ + public static final String KNOWN_INTEGER_RANGE = "KNOWN_INTEGER_RANGE"; + + /** + * Initialise the calculator with same or unknown alphabet size + */ + public void initialise(); + + /** + * Sets the samples from which to compute the PDF for the entropy. + * Should only be called once, the last call contains the + * observations that are used (they are not accumulated). + * + * @param observations array of (univariate) samples + * @throws Exception + */ + public void setObservations(Object[] observations) throws Exception; + + /** + * Signal that we will add in the samples for computing the PDF + * from several disjoint time-series or trials via calls to + * "addObservations" rather than "setObservations" type methods + * (defined by the child interfaces and classes). + */ + public void startAddObservations(); + + /** + * Signal that the observations are now all added, PDFs can now be constructed. + * + * @throws Exception when the estimator has no observations. + */ + public void finaliseAddObservations() throws Exception; + + /** + * Add observations in to our estimates of the pdfs. + * Univariate. + * + * @param states series of samples + */ + public void addObservations(int[] states); + + + /** + * Compute the average value of the measure + * from the previously-supplied samples. + * + * Must set average, min and max + * + * @return the estimate of the measure + */ + public double computeAverageLocalOfObservations(); + + /** + * Computes local information theoretic measure for the given + * states, using pdfs built up from observations previously + * sent in via the addObservations method. + * + * Must set average, min and max + * + * @param states time series of samples + * @return time-series of local values (indexed as per states) + */ + public double[] computeLocalFromPreviousObservations(int states[]); + + /** + * Standalone routine to + * compute the average information theoretic measure across a time-series + * of states. + * Return the average. + * + * @param states time series of samples + * @return average of the information-theoretic measure. + * @throws Exception if states parameter is empty. + */ + public double computeAverageLocal(int states[]) throws Exception; + + /** + * Add observations in to our estimates of the pdfs. + * This call suitable only for homogeneous agents, as all + * agents will contribute to the PDFs. + * + * @param states multivariate time series + * (1st index is time, 2nd index is variable number) + */ + @Deprecated + public void addObservations(int states[][]) throws Exception; + + /** + * Initialise the calculator with (potentially) a new alphabet size + * + * Deprecated, use initialise() and setProperty("ALPHABET_SIZE", "n") instead. + * @deprecated + * @param alphabetSize + */ + @Deprecated + public void initialise(int alphabetSize); +} diff --git a/java/source/infodynamics/measures/discrete/SingleAgentMeasureDiscreteInContextOfPastCalculator.java b/java/source/infodynamics/measures/discrete/UnivariateMeasureDiscreteInContextOfPastCalculator.java old mode 100755 new mode 100644 similarity index 61% rename from java/source/infodynamics/measures/discrete/SingleAgentMeasureDiscreteInContextOfPastCalculator.java rename to java/source/infodynamics/measures/discrete/UnivariateMeasureDiscreteInContextOfPastCalculator.java index d9af593..253af5d --- a/java/source/infodynamics/measures/discrete/SingleAgentMeasureDiscreteInContextOfPastCalculator.java +++ b/java/source/infodynamics/measures/discrete/UnivariateMeasureDiscreteInContextOfPastCalculator.java @@ -1,150 +1,190 @@ -/* - * Java Information Dynamics Toolkit (JIDT) - * Copyright (C) 2012, Joseph T. Lizier - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package infodynamics.measures.discrete; - -/** - * A base class for calculators computing measures for - * a single variable which - * require knowledge of the embedded past state of a univariate - * discrete (ie int[]) variable. - * - *

This combines functionality for single agents from - * {@link SingleAgentMeasureDiscrete} with functionality - * required in the context of the past provided by - * {@link ContextOfPastMeasureCalculatorDiscrete}.

- * - *

Usage is as defined in {@link InfoMeasureCalculatorDiscrete}, with - * extra methods for supplying observations and making - * calculations defined in {@link SingleAgentMeasureDiscrete}

. - * - *

Users should not need to deal with this class directly; - * it is simply used to gather common functionality for several - * child classes. - *

- * - * TODO Make the Active info storage and entropy calculators inherit from this - * - * @author Joseph Lizier (email, - * www) - */ -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 - * - * @param base number of quantisation levels for each variable. - * E.g. binary variables are in base-2. - * @param history embedding length - */ - 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(); - addObservations(states); - return computeLocalFromPreviousObservations(states); - } - - @Override - public final double[][] computeLocal(int[][] states) { - initialise(); - addObservations(states); - return computeLocalFromPreviousObservations(states); - } - - @Override - public final double[][][] computeLocal(int[][][] states) { - initialise(); - addObservations(states); - return computeLocalFromPreviousObservations(states); - } - - @Override - public final double computeAverageLocal(int[] states) { - initialise(); - addObservations(states); - return computeAverageLocalOfObservations(); - } - - @Override - public final double computeAverageLocal(int[][] states) { - initialise(); - addObservations(states); - return computeAverageLocalOfObservations(); - } - - @Override - public final double computeAverageLocal(int[][][] states) { - initialise(); - addObservations(states); - return computeAverageLocalOfObservations(); - } - - @Override - public final double[] computeLocal(int[][] states, int col) { - initialise(); - addObservations(states, col); - return computeLocalFromPreviousObservations(states, col); - } - - @Override - public final double[] computeLocal(int[][][] states, int index1, int index2) { - initialise(); - addObservations(states, index1, index2); - return computeLocalFromPreviousObservations(states, index1, index2); - } - - @Override - public final double computeAverageLocal(int[][] states, int col) { - initialise(); - addObservations(states, col); - return computeAverageLocalOfObservations(); - } - - @Override - public final double computeAverageLocal(int[][][] states, int index1, int index2) { - initialise(); - addObservations(states, index1, index2); - return computeAverageLocalOfObservations(); - } -} +/* + * Java Information Dynamics Toolkit (JIDT) + * Copyright (C) 2012, Joseph T. Lizier + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package infodynamics.measures.discrete; + +/** + * A base class for calculators computing measures for + * a single variable which + * require knowledge of the embedded past state of a univariate + * discrete (ie int[]) variable. + * + *

This combines functionality for single agents from + * {@link UnivariateMeasureDiscrete} with functionality + * required in the context of the past provided by + * {@link ContextOfPastMeasureCalculatorDiscrete}.

+ * + *

Usage is as defined in {@link InfoMeasureCalculatorDiscrete}, with + * extra methods for supplying observations and making + * calculations defined in {@link UnivariateMeasureDiscrete}

. + * + *

Users should not need to deal with this class directly; + * it is simply used to gather common functionality for several + * child classes. + *

+ * + * TODO Make the Active info storage and entropy calculators inherit from this + * + * @author Joseph Lizier (email, + * www) + */ +public abstract class UnivariateMeasureDiscreteInContextOfPastCalculator extends + ContextOfPastMeasureCalculatorDiscrete implements UnivariateMeasureDiscrete { + + /** + * Construct the calculator with default base of 2 and history 1 + */ + public UnivariateMeasureDiscreteInContextOfPastCalculator() { + super(2, 1); + } + + /** + * Construct the calculator + * + * @param base number of quantisation levels for each variable. + * E.g. binary variables are in base-2. + * @param history embedding length + */ + public UnivariateMeasureDiscreteInContextOfPastCalculator(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 UnivariateMeasureDiscreteInContextOfPastCalculator(int base, int history, boolean dontCreateObsStorage) { + super(base, history, dontCreateObsStorage); + } + + + public final double[] computeLocal(int[] states) { + initialise(); + addObservations(states); + return computeLocalFromPreviousObservations(states); + } + + @Override + public final double computeAverageLocal(int[] states) { + initialise(); + addObservations(states); + return computeAverageLocalOfObservations(); + } + + public final double[][] computeLocal(int[][] states) { + initialise(); + try { + addObservations(states); + } catch (Exception e) { + throw new RuntimeException(e); + } + return computeLocalFromPreviousObservations(states); + } + + public final double[][][] computeLocal(int[][][] states) { + initialise(); + addObservations(states); + return computeLocalFromPreviousObservations(states); + } + + public final double computeAverageLocal(int[][] states) { + initialise(); + try { + addObservations(states); + } catch (Exception e) { + throw new RuntimeException(e); + } + return computeAverageLocalOfObservations(); + } + + public final double computeAverageLocal(int[][][] states) { + initialise(); + addObservations(states); + return computeAverageLocalOfObservations(); + } + + public final double[] computeLocal(int[][] states, int col) { + initialise(); + addObservations(states, col); + return computeLocalFromPreviousObservations(states, col); + } + + public final double[] computeLocal(int[][][] states, int index1, int index2) { + initialise(); + addObservations(states, index1, index2); + return computeLocalFromPreviousObservations(states, index1, index2); + } + + public final double computeAverageLocal(int[][] states, int col) { + initialise(); + addObservations(states, col); + return computeAverageLocalOfObservations(); + } + + public final double computeAverageLocal(int[][][] states, int index1, int index2) { + initialise(); + addObservations(states, index1, index2); + return computeAverageLocalOfObservations(); + } + + // these are only here to get this thing to compile, they were in + // the interface, and maybe I could or should have done this in the classes + // that don't need them at all, but whatever, I think these should be + // removed or only added to the classes that need them. + + private double[][] computeLocalFromPreviousObservations(int[][] states) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'computeLocalFromPreviousObservations'"); + } + + private void addObservations(int[][][] states) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'addObservations'"); + } + + private double[][][] computeLocalFromPreviousObservations(int[][][] states) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'computeLocalFromPreviousObservations'"); + } + + private double[] computeLocalFromPreviousObservations(int[][] states, int col) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'computeLocalFromPreviousObservations'"); + } + + private double[] computeLocalFromPreviousObservations(int[][][] states, int index1, int index2) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'computeLocalFromPreviousObservations'"); + } + + private void addObservations(int[][] states, int col) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'addObservations'"); + } + + private void addObservations(int[][][] states, int index1, int index2) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'addObservations'"); + } +} diff --git a/java/unittests/infodynamics/measures/discrete/EntropyTester.java b/java/unittests/infodynamics/measures/discrete/EntropyTester.java new file mode 100644 index 0000000..7767d83 --- /dev/null +++ b/java/unittests/infodynamics/measures/discrete/EntropyTester.java @@ -0,0 +1,196 @@ +package infodynamics.measures.discrete; + +import static org.junit.Assert.assertThrows; + +import org.junit.Test; + +import infodynamics.measures.discrete.InfoMeasureCalculatorDiscrete.State; +import junit.framework.TestCase; + +import java.util.Arrays; +import java.util.List; + +public class EntropyTester extends TestCase { + + private EntropyCalculatorDiscrete calc; + private static double ERR_ALLOWANCE = 0.02; + + public void setup() { + calc = new EntropyCalculatorDiscrete(); + } + + @Test + public void testHashTableUseBasic() throws Exception { + setup(); + + // 1. check the state machine is in the correct state + assertEquals(State.SETTING_PROPERTIES, calc.currentState); + + calc.initialise(); + String[] obs = new String[] {"a", "b", "b"}; + calc.addObservations(obs); + + // 2. check that the integer range is infact unknown + // 3. check the state machine + assertEquals(false, calc.knownIntegerRange); + assertEquals(State.ADDING_OBSERVATIONS, calc.currentState); + + // 4. check the hash table and it's values + assertEquals((Integer) 1, calc.hashedStateCount.get("a")); + assertEquals((Integer) 2, calc.hashedStateCount.get("b")); + + double ent = calc.computeAverageLocalOfObservations(); + + // 5. check result of entropy calculations - allowing small error margin + assertTrue(Math.abs(ent-0.918)/0.918 <= ERR_ALLOWANCE); + assertEquals(State.COMPUTING, calc.currentState); + } + + @Test + public void testArrayUseBasic() throws Exception { + setup(); + calc.setProperty("ALPHABET_SIZE", "2"); + + assertEquals(State.SETTING_PROPERTIES, calc.currentState); + assertEquals(true, calc.knownIntegerRange); + + int[] obs = new int[] {0,0,1,1}; + calc.addObservations(obs); + + assertEquals(State.ADDING_OBSERVATIONS, calc.currentState); + + double ent = calc.computeAverageLocalOfObservations(); + assertEquals(1.0, ent); + assertEquals(State.COMPUTING, calc.currentState); + } + + @Test + public void testArrayUseOverflowAlphaSize() throws Exception { + setup(); + calc.setProperty("ALPHABET_SIZE", "2"); + + int[] obs = new int[] { 0, 1, 2 }; + assertThrows(RuntimeException.class, () -> { + calc.addObservations(obs); + }); + } + + @Test + public void testArrayUseOverflowAlphaSize2() throws Exception { + setup(); + calc.setProperty("ALPHABET_SIZE", "2"); + + Integer[] obs = new Integer[] { 0, 1, 2 }; + assertThrows(RuntimeException.class, () -> { + calc.addObservations(obs); + }); + } + + @Test + public void testStringIntegerInterpretation() throws Exception { + setup(); + calc.setProperty("ALPHABET_SIZE", "2"); + + String[] obs = new String[] { "0", "1", "1" }; + calc.addObservations(obs); + + double ent = calc.computeAverageLocalOfObservations(); + + // ensure we did use the array implementation + assertEquals(calc.knownIntegerRange, true); + assertNotNull(calc.stateCount); + assertTrue(calc.hashedStateCount.isEmpty()); + + // ensure it gets correct output - allowing small error margin + assertTrue(Math.abs(ent-0.918)/0.918 <= ERR_ALLOWANCE); + } + + @Test + public void testUninterpretableInput() throws Exception { + setup(); + calc.setProperty("ALPHABET_SIZE", "2"); + + String[] obs = new String[] { "0", "1", "a" }; + + // we specified an alphabet size, but cannot interpret "a" as an integer + assertThrows(RuntimeException.class, () ->{ + calc.addObservations(obs); + }); + } + + @Test + public void testNegativeNums() throws Exception { + setup(); + + calc.setProperty("ALPHABET_SIZE", "4"); + int[] obs = new int[] { 0, 1, -1, 2 }; + + // Negative numbers are invalid observations. + assertThrows(RuntimeException.class, () -> { + calc.addObservations(obs); + }); + } + + @Test + public void testExceedMaxAlphaSize() throws Exception { + setup(); + + // TODO -- This test is under the assumption of the temporary max alphabet size of 100 + // when this number is solidified, this test needs to change (it will fail when it does change.) + int[] obs = new int[] { 99, 100, 101 }; + calc.addObservations(obs); + + assertFalse(calc.hashedStateCount.isEmpty()); + assertNull(calc.stateCount); + } + + @Test + public void testMultiDimensionalIntObservations() throws Exception { + setup(); + + calc.setProperty("NUM_DIMENSIONS", "3"); + + int[][] obs = new int[][] { + {1, 2, 3}, + {4, 5, 6}, + {1, 2, 3} + }; + + calc.addObservations(obs); + + // TODO -- compute combined values + + + // assertEquals((Integer) 2, calc.hashedStateCount.get(test1)); + // assertEquals((Integer) 1, calc.hashedStateCount.get(test2)); + } + + @Test + public void testMultiDimensionalObjObservations() throws Exception { + setup(); + + calc.setProperty("NUM_DIMENSIONS", "3"); + + Object[][] obs = new Object[][] { + {"A", "B", "C"}, + {"D", "E", "F"}, + {"A", "B", "C"} + }; + + calc.addObservations(obs); + + List test1 = Arrays.asList(obs[0]); + List test2 = Arrays.asList(obs[1]); + + assertEquals((Integer) 2, calc.hashedStateCount.get(test1)); + assertEquals((Integer) 1, calc.hashedStateCount.get(test2)); + } + + // TODO -- implement this test. + @Test + public void testZeroDimensions() throws Exception { + setup(); + + calc.setProperty("NUM_DIMENSIONS", "0"); + } +}