diff --git a/java/source/infodynamics/measures/discrete/ActiveInformationCalculator.java b/java/source/infodynamics/measures/discrete/ActiveInformationCalculator.java index 80f61fa..39fc381 100755 --- a/java/source/infodynamics/measures/discrete/ActiveInformationCalculator.java +++ b/java/source/infodynamics/measures/discrete/ActiveInformationCalculator.java @@ -1,7 +1,9 @@ package infodynamics.measures.discrete; +import infodynamics.utils.EmpiricalMeasurementDistribution; import infodynamics.utils.MathsUtils; import infodynamics.utils.MatrixUtils; +import infodynamics.utils.RandomGenerator; /** * Usage: @@ -361,7 +363,8 @@ public class ActiveInformationCalculator { } /** - * Computes local active info storage for the given values + * Computes local active info storage for the given (single) + * specific values * * @param destNext * @param destPast @@ -863,6 +866,77 @@ public class ActiveInformationCalculator { return computeAverageLocalOfObservations(); } + /** + * Compute the significance of obtaining the given average from the given observations + * + * @param numPermutationsToCheck number of new orderings of the source values to compare against + * @return + */ + public EmpiricalMeasurementDistribution computeSignificance(int numPermutationsToCheck) { + RandomGenerator rg = new RandomGenerator(); + // (Not necessary to check for distinct random perturbations) + int[][] newOrderings = rg.generateRandomPerturbations(observations, numPermutationsToCheck); + return computeSignificance(newOrderings); + } + + /** + * Compute the significance of obtaining the given average from the given observations + * + * @param newOrderings the reorderings to use + * @return + */ + public EmpiricalMeasurementDistribution computeSignificance(int[][] newOrderings) { + double actualMI = computeAverageLocalOfObservations(); + + int numPermutationsToCheck = newOrderings.length; + + // Reconstruct the values of the previous and next variables (not necessarily in order) + int[] prevValues = new int[observations]; + int[] nextValues = new int[observations]; + int t_prev = 0; + int t_next = 0; + for (int prevVal = 0; prevVal < prevCount.length; prevVal++) { + int numberOfSamplesPrev = prevCount[prevVal]; + MatrixUtils.fill(prevValues, prevVal, t_prev, numberOfSamplesPrev); + t_prev += numberOfSamplesPrev; + } + for (int nextVal = 0; nextVal < base; nextVal++) { + int numberOfSamplesNext = nextCount[nextVal]; + MatrixUtils.fill(nextValues, nextVal, t_next, numberOfSamplesNext); + t_next += numberOfSamplesNext; + } + + ActiveInformationCalculator ais2; + ais2 = new ActiveInformationCalculator(base, k); + ais2.initialise(); + ais2.observations = observations; + ais2.prevCount = prevCount; + ais2.nextCount = nextCount; + int countWhereMIIsMoreSignificantThanOriginal = 0; + EmpiricalMeasurementDistribution measDistribution = new EmpiricalMeasurementDistribution(numPermutationsToCheck); + for (int p = 0; p < numPermutationsToCheck; p++) { + // Generate a new re-ordered data set for the next variable + int[] newDataNext = MatrixUtils.extractSelectedTimePoints(nextValues, newOrderings[p]); + // compute the joint probability distribution + MatrixUtils.fill(ais2.jointCount, 0); + for (int t = 0; t < observations; t++) { + ais2.jointCount[newDataNext[t]][prevValues[t]]++; + } + // And get an MI value for this realisation: + double newMI = ais2.computeAverageLocalOfObservations(); + measDistribution.distribution[p] = newMI; + if (newMI >= actualMI) { + countWhereMIIsMoreSignificantThanOriginal++; + } + + } + + // And return the significance + measDistribution.pValue = (double) countWhereMIIsMoreSignificantThanOriginal / (double) numPermutationsToCheck; + measDistribution.actualValue = actualMI; + return measDistribution; + } + public double getLastAverage() { return average; } diff --git a/java/source/infodynamics/measures/discrete/BlockEntropyCalculator.java b/java/source/infodynamics/measures/discrete/BlockEntropyCalculator.java index 21ac8c3..eacf4e6 100755 --- a/java/source/infodynamics/measures/discrete/BlockEntropyCalculator.java +++ b/java/source/infodynamics/measures/discrete/BlockEntropyCalculator.java @@ -82,6 +82,39 @@ public class BlockEntropyCalculator extends EntropyCalculator { } + /** + * Add observations in to our estimates of the pdfs. + * + * @param states index is time + */ + public void addObservations(int states[]) { + int rows = states.length; + // increment the count of observations: + observations += (rows - blocksize + 1); + + // Initialise and store the current previous value + int stateVal = 0; + for (int p = 0; p < blocksize - 1; p++) { + // Add the contribution from this observation + stateVal += states[p]; + // And shift up + stateVal *= base; + } + + // 1. Now count the tuples observed from the next row onwards + for (int r = blocksize - 1; r < rows; r++) { + // Add the contribution from this observation + stateVal += states[r]; + + // Add to the count for this particular state: + stateCount[stateVal]++; + + // Remove the oldest observation from the state value + stateVal -= maxShiftedValue[states[r-blocksize+1]]; + stateVal *= base; + } + } + /** * Add observations in to our estimates of the pdfs. * This call suitable only for homogeneous agents, as all diff --git a/java/source/infodynamics/measures/discrete/EntropyCalculator.java b/java/source/infodynamics/measures/discrete/EntropyCalculator.java index 1f5e95d..6f3512e 100755 --- a/java/source/infodynamics/measures/discrete/EntropyCalculator.java +++ b/java/source/infodynamics/measures/discrete/EntropyCalculator.java @@ -25,7 +25,6 @@ import infodynamics.utils.MatrixUtils; * *

* - * TODO Add method calls for single dimensional arrays * * @author Joseph Lizier */ @@ -78,6 +77,23 @@ public class EntropyCalculator extends InfoMeasureCalculator } + /** + * Add observations in to our estimates of the pdfs. + * + * @param states 1st index is time + */ + 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]]++; + } + } + /** * Add observations in to our estimates of the pdfs. * This call suitable only for homogeneous agents, as all @@ -226,6 +242,38 @@ public class EntropyCalculator extends InfoMeasureCalculator return ent; } + /** + * Computes local entropy for the given + * states, using pdfs built up from observations previously + * sent in via the addObservations method + * + * @param states index is time + * @return + */ + public double[] computeLocalFromPreviousObservations(int states[]){ + int rows = states.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]] / (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; + + } + /** * Computes local entropy for the given * states, using pdfs built up from observations previously @@ -239,7 +287,6 @@ public class EntropyCalculator extends InfoMeasureCalculator int rows = states.length; int columns = states[0].length; - // Allocate for all rows even though we may not be assigning all of them double[][] localEntropy = new double[rows][columns]; average = 0; max = 0; @@ -287,7 +334,6 @@ public class EntropyCalculator extends InfoMeasureCalculator } } - // Allocate for all rows even though we may not be assigning all of them double[][][] localEntropy = new double[timeSteps][agentRows][agentColumns]; average = 0; max = 0; @@ -327,7 +373,6 @@ public class EntropyCalculator extends InfoMeasureCalculator int rows = 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[rows]; average = 0; max = 0; @@ -386,6 +431,23 @@ public class EntropyCalculator extends InfoMeasureCalculator } + /** + * Standalone routine to + * compute local information theoretic measure across a 1D temporal + * array of the states of homogeneous agents + * Return a 1D temporal array of local values. + * First history rows are zeros + * + * @param states - 1D array of states + * @return + */ + public final double[] computeLocal(int states[]) { + + initialise(); + addObservations(states); + return computeLocalFromPreviousObservations(states); + } + /** * Standalone routine to * compute local information theoretic measure across a 2D spatiotemporal @@ -420,6 +482,22 @@ public class EntropyCalculator extends InfoMeasureCalculator return computeLocalFromPreviousObservations(states); } + /** + * Standalone routine to + * compute average local information theoretic measure across a 1D temporal + * array of the states of homogeneous agents + * Return the average + * + * @param states - 1D array of states + * @return + */ + public final double computeAverageLocal(int states[]) { + + initialise(); + addObservations(states); + return computeAverageLocalOfObservations(); + } + /** * Standalone routine to * compute average local information theoretic measure across a 2D spatiotemporal diff --git a/java/source/infodynamics/measures/discrete/MutualInformationCalculator.java b/java/source/infodynamics/measures/discrete/MutualInformationCalculator.java index 5fdef84..718dfd5 100755 --- a/java/source/infodynamics/measures/discrete/MutualInformationCalculator.java +++ b/java/source/infodynamics/measures/discrete/MutualInformationCalculator.java @@ -221,6 +221,32 @@ public class MutualInformationCalculator extends InfoMeasureCalculator return measDistribution; } + /** + * Computes local mutual information (or pointwise mutual information) + * for the given (single) specific values, using pdfs built up from observations previously + * sent in via the addObservations method. + * + * @param val1 single specific value of variable 1 + * @param val2 single specific value of variable 2 + * @return a local mutual information value for this pair of observations + * @throws Exception if this pair were not observed together in the + * previously supplied observations + */ + public double computeLocalFromPreviousObservations(int val1, int val2) throws Exception{ + + double logTerm = ( (double) jointCount[val1][val2] ) / + ( (double) jCount[val2] * + (double) iCount[val1] ); + // 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; + double localMI = Math.log(logTerm) / log_2; + + return localMI; + } + /** * Computes local mutual information (or pointwise mutual information) * for the given states, using pdfs built up from observations previously