From f006c53e463bf7feca5012f25cd63f4f50afde70 Mon Sep 17 00:00:00 2001 From: "joseph.lizier" Date: Fri, 7 Jun 2013 05:58:47 +0000 Subject: [PATCH] Adding python examples 5 and 6. Minor tweaks to octave examples 5 and 6 to clarify comments or minor conflicts. Error corrected in comment of python example 2 --- .../octave/example5TeBinaryMultivarTransfer.m | 9 ++- .../octave/example6DynamicCallingMutualInfo.m | 2 +- demos/python/example2TeMultidimBinaryData.py | 2 +- .../example5TeBinaryMultivarTransfer.py | 41 ++++++++++ .../example6DynamicCallingMutualInfo.py | 79 +++++++++++++++++++ 5 files changed, 127 insertions(+), 6 deletions(-) create mode 100755 demos/python/example5TeBinaryMultivarTransfer.py create mode 100755 demos/python/example6DynamicCallingMutualInfo.py diff --git a/demos/octave/example5TeBinaryMultivarTransfer.m b/demos/octave/example5TeBinaryMultivarTransfer.m index 042fa68..7f1c28b 100755 --- a/demos/octave/example5TeBinaryMultivarTransfer.m +++ b/demos/octave/example5TeBinaryMultivarTransfer.m @@ -8,11 +8,12 @@ javaaddpath('../../infodynamics.jar'); % Generate some random binary data. % Note that we need the *1 to make this a number not a Boolean, % otherwise this will not work (as it cannot match the method signature) -sourceArray=(rand(1000,2)>0.5)*1; -sourceArray2=(rand(1000,2)>0.5)*1; +numObservations = 100; +sourceArray=(rand(numObservations,2)>0.5)*1; +sourceArray2=(rand(numObservations,2)>0.5)*1; % Destination variable takes a copy of the first bit of the source in bit 1, % and an XOR of the two bits of the source in bit 2: -destArray = [0, 0; sourceArray(1:99, 1), xor(sourceArray(1:99, 1), sourceArray(1:99, 2))]; +destArray = [0, 0; sourceArray(1:numObservations-1, 1), xor(sourceArray(1:numObservations-1, 1), sourceArray(1:numObservations-1, 2))]; % Create a TE calculator and run it: teCalc=javaObject('infodynamics.measures.discrete.ApparentTransferEntropyCalculator', 4, 1); teCalc.initialise(); @@ -28,5 +29,5 @@ teCalc.addObservations(mUtils.computeCombinedValues(octaveToJavaDoubleMatrix(des mUtils.computeCombinedValues(octaveToJavaDoubleMatrix(sourceArray2), 2)); fprintf('For random source, result should be close to 0 bits in theory: '); result2 = teCalc.computeAverageLocalOfObservations() -fprintf('\nThe result for random source is inflated towards 0.3 due to finite observation length. One can verify that the answer is consistent with that from a random source by checking: teCalc.computeSignificance(1000); ans.pValue\n'); +fprintf('\nThe result for random source is inflated towards 0.3 due to finite observation length (%d). One can verify that the answer is consistent with that from a random source by checking: teCalc.computeSignificance(1000); ans.pValue\n', teCalc.getNumObservations()); diff --git a/demos/octave/example6DynamicCallingMutualInfo.m b/demos/octave/example6DynamicCallingMutualInfo.m index f84d874..9325c7e 100755 --- a/demos/octave/example6DynamicCallingMutualInfo.m +++ b/demos/octave/example6DynamicCallingMutualInfo.m @@ -25,7 +25,7 @@ variable2Columns = [3,4]; % infodynamics.measures.continuous.MutualInfoCalculatorMultiVariate % which we wish to use for the calculation. % Note that one could use any of the following calculators (try them all!): -% implementingClass = "infodynamics.measures.continuous.kraskov.MutualInfoCalculatorMultiVariateKraskov1"; +% implementingClass = "infodynamics.measures.continuous.kraskov.MutualInfoCalculatorMultiVariateKraskov1"; % MI([1,2], [3,4]) = 0.35507 % implementingClass = "infodynamics.measures.continuous.kernel.MutualInfoCalculatorMultiVariateKernel"; % implementingClass = "infodynamics.measures.continuous.gaussian.MutualInfoCalculatorMultiVariateGaussian"; implementingClass = "infodynamics.measures.continuous.kraskov.MutualInfoCalculatorMultiVariateKraskov1"; diff --git a/demos/python/example2TeMultidimBinaryData.py b/demos/python/example2TeMultidimBinaryData.py index bfc4a69..465a442 100755 --- a/demos/python/example2TeMultidimBinaryData.py +++ b/demos/python/example2TeMultidimBinaryData.py @@ -13,7 +13,7 @@ jarLocation = "../../infodynamics.jar" startJVM(getDefaultJVMPath(), "-ea", "-Djava.class.path=" + jarLocation) # Create many columns in a multidimensional array, e.g. for fully random values: -# twoDTimeSeriesOctave = [[random.randint(0,1)]*2 for x in xrange(10)] # for 10 rows (time-steps) for 2 variables +# twoDTimeSeriesOctave = [[random.randint(0,1) for y in xrange(2)] for x in xrange(10)] # for 10 rows (time-steps) for 2 variables # However here we want 2 rows by 100 columns where the next time step (row 2) is to copy the # value of the column on the left from the previous time step (row 1): diff --git a/demos/python/example5TeBinaryMultivarTransfer.py b/demos/python/example5TeBinaryMultivarTransfer.py new file mode 100755 index 0000000..f45d0b4 --- /dev/null +++ b/demos/python/example5TeBinaryMultivarTransfer.py @@ -0,0 +1,41 @@ +# = Example 5 - Multivariate transfer entropy on binary data = + +# Multivariate transfer entropy (TE) calculation on binary data using the discrete TE calculator: + +from jpype import * +import random +from operator import xor + +# Change location of jar to match yours: +jarLocation = "../../infodynamics.jar" +# Start the JVM (add the "-Xmx" option with say 1024M if you get crashes due to not enough memory space) +startJVM(getDefaultJVMPath(), "-ea", "-Djava.class.path=" + jarLocation) + +# Generate some random binary data. +numObservations = 100 +sourceArray = [[random.randint(0,1) for y in xrange(2)] for x in xrange(numObservations)] # for 10 rows (time-steps) for 2 variables +sourceArray2= [[random.randint(0,1) for y in xrange(2)] for x in xrange(numObservations)] # for 10 rows (time-steps) for 2 variables +# Destination variable takes a copy of the first bit of the source in bit 1, +# and an XOR of the two bits of the source in bit 2: +destArray = [[0, 0]] +for j in range(1,numObservations): + destArray.append([sourceArray[j-1][0], xor(sourceArray[j-1][0], sourceArray[j-1][1])]) + +# Create a TE calculator and run it: +teCalcClass = JPackage("infodynamics.measures.discrete").ApparentTransferEntropyCalculator +teCalc = teCalcClass(4,1) +teCalc.initialise() +# We need to construct the joint values of the dest and source before we pass them in, +# and need to use the matrix conversion routine when calling from Matlab/Octave: +mUtils= JPackage('infodynamics.utils').MatrixUtils +teCalc.addObservations(mUtils.computeCombinedValues(destArray, 2), \ + mUtils.computeCombinedValues(sourceArray, 2)) +result = teCalc.computeAverageLocalOfObservations() +print('For source which the 2 bits are determined from, result should be close to 2 bits : %.3f' % result) +teCalc.initialise() +teCalc.addObservations(mUtils.computeCombinedValues(destArray, 2), \ + mUtils.computeCombinedValues(sourceArray2, 2)) +result2 = teCalc.computeAverageLocalOfObservations() +print('For random source, result should be close to 0 bits in theory: %.3f' % result2) +print('The result for random source is inflated towards 0.3 due to finite observation length (%d). One can verify that the answer is consistent with that from a random source by checking: teCalc.computeSignificance(1000); ans.pValue\n' % teCalc.getNumObservations()) + diff --git a/demos/python/example6DynamicCallingMutualInfo.py b/demos/python/example6DynamicCallingMutualInfo.py new file mode 100755 index 0000000..e847737 --- /dev/null +++ b/demos/python/example6DynamicCallingMutualInfo.py @@ -0,0 +1,79 @@ +# = Example 6 - Mutual information calculation with dynamic specification of calculator = + +# This example shows how to write Python code to take advantage of the +# common interfaces defined for various information-theoretic calculators. +# Here, we use the common form of the infodynamics.measures.continuous.MutualInfoCalculatorMultiVariate +# interface (which is never named here) to write common code into which we can plug +# one of three concrete implementations (kernel estimator, Kraskov estimator or +# linear-Gaussian estimator) by dynamically supplying the class name of +# the concrete implementation. +# +# This is the Python equivalent to the demos/java/lateBindingDemo + +from jpype import * +import random +import string +import numpy + +# Change location of jar to match yours: +jarLocation = "../../infodynamics.jar" +# Start the JVM (add the "-Xmx" option with say 1024M if you get crashes due to not enough memory space) +startJVM(getDefaultJVMPath(), "-ea", "-Djava.class.path=" + jarLocation) + +#--------------------- +# 1. Properties for the calculation (these are dynamically changeable): +# The name of the data file (relative to this directory) +datafile = '../data/4ColsPairedNoisyDependence-1.txt' +# List of column numbers for variables 1 and 2: +# (you can select any columns you wish to be contained in each variable) +variable1Columns = [0,1] # array indices start from 0 in python +variable2Columns = [2,3] +# The name of the concrete implementation of the interface +# infodynamics.measures.continuous.MutualInfoCalculatorMultiVariate +# which we wish to use for the calculation. +# Note that one could use any of the following calculators (try them all!): +# implementingClass = "infodynamics.measures.continuous.kraskov.MutualInfoCalculatorMultiVariateKraskov1" # MI([0,1], [2,3]) = 0.35507 +# implementingClass = "infodynamics.measures.continuous.kernel.MutualInfoCalculatorMultiVariateKernel" +# implementingClass = "infodynamics.measures.continuous.gaussian.MutualInfoCalculatorMultiVariateGaussian" +implementingClass = "infodynamics.measures.continuous.kraskov.MutualInfoCalculatorMultiVariateKraskov1" + +#--------------------- +# 2. Load in the data (space separate numbers, one time step per line, each column is a variable) +f = open(datafile) +data = [] +for line in f: + data.append([float(x) for x in line.split()]) + +# As numpy array: +A = numpy.array(data) + +# Pull out the columns from the data set which correspond to each of variable 1 and 2: +variable1 = A[:,variable1Columns] +variable2 = A[:,variable2Columns] + +#-------------------- +# 3. Dynamically instantiate an object of the given class: +# (in fact, all java object creation in python is dynamic - it has to be, +# since the languages are interpreted. This makes our life slightly easier at this +# point than it is in demos/java/lateBindingDemo where we have to handle this manually) +indexOfLastDot = string.rfind(implementingClass, ".") +implementingPackage = implementingClass[:indexOfLastDot] +implementingBaseName = implementingClass[indexOfLastDot+1:] +miCalcClass = eval('JPackage(\'%s\').%s' % (implementingPackage, implementingBaseName)) +miCalc = miCalcClass() + +#-------------------- +# 4. Start using the MI calculator, paying attention to only +# call common methods defined in the interface type +# infodynamics.measures.continuous.MutualInfoCalculatorMultiVariate +# not methods only defined in a given implementation class. +# a. Initialise the calculator to use the required number of +# dimensions for each variable: +miCalc.initialise(len(variable1Columns), len(variable2Columns)) +# b. Supply the observations to compute the PDFs from: +miCalc.setObservations(variable1, variable2) +# c. Make the MI calculation: +miValue = miCalc.computeAverageLocalOfObservations() + +print("MI calculator %s computed the joint MI as %.5f\n" % (implementingClass, miValue)) +