Added functions to discrete Entropy calculators for single dimensional arrays, plus local values of MI for single supplied values and statistical signficance testing for Active info storage.

This commit is contained in:
joseph.lizier 2014-03-26 04:08:44 +00:00
parent 3e017d1be4
commit 06d0ddf07d
4 changed files with 216 additions and 5 deletions

View File

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

View File

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

View File

@ -25,7 +25,6 @@ import infodynamics.utils.MatrixUtils;
* </li>
* </ol></p>
*
* 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

View File

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