jidt/demos/octave/DetectingInteractionLags/transferWithSourceMemory.m

214 lines
9.2 KiB
Matlab
Executable File

%%
%% 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 <http://www.gnu.org/licenses/>.
%%
% Compute the transfer entropy (te) and the Pompe-Runge Momentary information transfer (mit)
% in an example where we have short-term source memory (with decay).
%
% The model is:
% X_{n-1} + noise -> X_{n} (noise represents new information entering the source)
% X_{n} -> Y_{n+1} (Y_{n+1} copies directly from X_{n} though is correlated to X_{n-1})
% We expect to find the connection X_{n} -> Y_{n+1} dominating, since it is
% causal, if our measure of transfer is correct. Indeed, the proof of Wibral
% et al. states that transfer entropy will be maximised here.
% We show that the Pompe-Runge Momentary information transfer is actually
% maximised for lag 2: X_{n-1} -> Y_{n+1}, for many noise levels instead
% (because for X_{n} -> Y_{n+1} it conditions out the memory from X_{n-1}),
% showing that it is not maximised
% for the correct delay even in such simple unidirectional coupling.
%
% This script takes 1-2 minutes to run and generate the plots.
%
% NOTE: You may need to increase the Java heap space in Matlab for this
% to work (you will get a "java.lang.OutOfMemoryError: Java heap space"
% error if this is a problem).
%
% Inputs:
% - savePlot - true if you want eps files of the plots saved
%
function transferWithSourceMemory(savePlot)
tic;
% Add utilities to the path
addpath('..');
% Assumes the jar is two levels up - change this if this is not the case
% Octave is happy to have the path added multiple times; I'm unsure if this is true for matlab
javaaddpath('../../../infodynamics.jar');
if (nargin < 1)
savePlot = false;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This section is here for description only:
% Possible states of source X
xValues = [0, 1, 2, 3];
% X is self-mapped to its own next state stochastically;
% - with probability 1-delta, one of the following occurs
% with a 50-50 probability (ordinary mapping):
xMapping1 = [0, 0, 1, 1];
xMapping2 = [2, 2, 3, 3];
% - or with probability delta, one of the following occurs
% with a 50-50 probability (noisy mapping):
% (note: noisy mapping removes the memory component)
xNoisyMapping1 = [1, 1, 0, 0];
xNoisyMapping2 = [3, 3, 2, 2];
% Y is mapped from X as:
yMapping = [0, 1, 0, 1];
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Empirical results
N = 1000000; % number of observations
% noise level (i.e. percent times that X_{n} is altered away from X_{n-1}
deltas = 0:0.01:0.5;
teXnToYnplus1 = zeros(1,length(deltas));
teXnminus1ToYnplus1 = zeros(1,length(deltas));
mitXnToYnplus1 = zeros(1,length(deltas));
mitXnminus1ToYnplus1 = zeros(1,length(deltas));
for deltaIndex = 1:length(deltas)
delta = deltas(deltaIndex);
% We can implement the (Y,X) process much faster by considering
% X as a joint variable (X2,X1) where X2 is updated at random at
% each time step, and X1 copies the previous value of X2 with
% probability delta, or inverts it with probability 1-delta:
x2 = rand(N+1,1)<0.5;
noisyMapping = rand(N,1)<delta;
x1 = [rand()<0.5; x2(1:N) .* (1 - noisyMapping) + not(x2(1:N)) .* noisyMapping];
x = x2*2+x1;
y = [rand() < 0.5; x1(1:N)];
% Compute TEs
teCalc = javaObject('infodynamics.measures.discrete.TransferEntropyCalculator', 4, 1);
teCalc.initialise();
teCalc.addObservations(x, y);
teXnToYnplus1(deltaIndex) = teCalc.computeAverageLocalOfObservations();
teCalc.initialise();
teCalc.addObservations(x(1:length(x)-1), y(2:length(y)));
teXnminus1ToYnplus1(deltaIndex) = teCalc.computeAverageLocalOfObservations();
% Compute MITs using a conditional TE calculator, adding the past of the source to the conditionals
compTeCalc = javaObject('infodynamics.measures.discrete.ConditionalTransferEntropyCalculator', 4, 1, 1);
compTeCalc.initialise();
% We need to additionally condition on the past of X:
compTeCalc.addObservations(octaveToJavaIntArray(x(2:length(x))), ...
octaveToJavaIntArray(y(2:length(y))), ...
octaveToJavaIntArray(x(1:length(x)-1)));
mitXnToYnplus1(deltaIndex) = compTeCalc.computeAverageLocalOfObservations();
compTeCalc.initialise();
% We need to shift x forward here to investigate the lag, and condition on the past of Y
compTeCalc.addObservations(octaveToJavaIntArray(x(2:length(x)-1)), ...
octaveToJavaIntArray(y(3:length(y))), ...
octaveToJavaIntArray(x(1:length(x)-2)));
mitXnminus1ToYnplus1(deltaIndex) = compTeCalc.computeAverageLocalOfObservations();
fprintf('delta=%.3f, TE(X_{n} -> Y_{n+1})=%.3f, TE(X_{n-1} -> Y_{n+1})=%.3f, MIT(X_{n} -> Y_{n+1})=%.3f, MIT(X_{n-1} -> Y_{n+1})=%.3f\n', ...
delta, teXnToYnplus1(deltaIndex), teXnminus1ToYnplus1(deltaIndex), ...
mitXnToYnplus1(deltaIndex), mitXnminus1ToYnplus1(deltaIndex));
end
% Analytic results:
teXnToYnplus1_an = ones(1, length(deltas));
teXnminus1ToYnplus1_an = 1 + (1 - deltas).*log2(1 - deltas) + ...
deltas .* log2(deltas);
mitXnToYnplus1_an = 1 - teXnminus1ToYnplus1_an;
mitXnminus1ToYnplus1_an = teXnminus1ToYnplus1_an;
% Plot the TEs
% plot types: h - open diamonds, d - closed diamonds, s - closed squares, p - open squares
markersize = 15;
figure;
if (exist ('OCTAVE_VERSION', 'builtin'))
% Make the full plots only on octave
if (savePlot)
set(gca, 'fontsize', 32); % do this first to get fontsize right for the key
end
plot(deltas, teXnToYnplus1, 'x1;Empirical: TE_{SPO}(X \rightarrow Y, 1);', 'markersize', markersize);
hold on;
plot(deltas, teXnToYnplus1_an, 'p1;Analytic: TE_{SPO}(X \rightarrow Y, 1);', 'markersize', markersize); % h plots open diamonds
plot(deltas, teXnminus1ToYnplus1, '+2;Empirical: TE_{SPO}(X \rightarrow y, 2);', 'markersize', markersize);
plot(deltas, teXnminus1ToYnplus1_an, 'o2;Analytic: TE_{SPO}(X \rightarrow Y, 2);', 'markersize', markersize);
hold off;
% Make figures ok for plotting:
legend('location', 'east');
if (savePlot)
xlabel('\eta', 'fontsize', 32);
ylabel('Information (bits)', 'fontsize', 32);
print('te.eps', '-deps', '-color');
else
% do these without fontsize to have more stable displays in octave
xlabel('\eta');
ylabel('Information (bits)');
end
else
% We're on Matlab - just make a quick plot
plot(deltas, teXnToYnplus1, 'rx', 'markersize', markersize); % Empirical: TE_{SPO}(X \rightarrow Y, 1);
hold on;
plot(deltas, teXnToYnplus1_an, 'rp', 'markersize', markersize); % Analytic: TE_{SPO}(X \rightarrow Y, 1)
plot(deltas, teXnminus1ToYnplus1, 'g+', 'markersize', markersize); % Empirical: TE_{SPO}(X \rightarrow y, 2)
plot(deltas, teXnminus1ToYnplus1_an, 'go', 'markersize', markersize); % Analytic: TE_{SPO}(X \rightarrow Y, 2)
hold off;
% Make figures ok for plotting:
legend('Empirical: TE_{SPO}(X \rightarrow Y, 1)', 'Analytic: TE_{SPO}(X \rightarrow Y, 1)', ...
'Empirical: TE_{SPO}(X \rightarrow y, 2)', 'Analytic: TE_{SPO}(X \rightarrow Y, 2)', ...
'Location', 'East');
end
% Plot the MIT's
figure;
if (exist ('OCTAVE_VERSION', 'builtin'))
% Make the full plots only on octave
if (savePlot)
set(gca, 'fontsize', 32); % do this first to get fontsize right for the key
end
plot(deltas, mitXnToYnplus1, 'x1;Empirical: MIT(X \rightarrow Y, 1);', 'markersize', markersize);
hold on;
plot(deltas, mitXnToYnplus1_an, 'p1;Analytic: MIT(X \rightarrow Y, 1);', 'markersize', markersize);
plot(deltas, mitXnminus1ToYnplus1, '+2;Empirical: MIT(X \rightarrow Y, 2);', 'markersize', markersize);
plot(deltas, mitXnminus1ToYnplus1_an, 'o2;Analytic: MIT(X \rightarrow Y, 2);', 'markersize', markersize);
hold off;
% Make figures ok for plotting:
legend('location', 'east')
if (savePlot)
xlabel('\eta', 'fontsize', 32);
ylabel('Information (bits)', 'fontsize', 32);
print('mit.eps', '-deps', '-color');
else
% do these without fontsize to have more stable displays in octave
xlabel('\eta');
ylabel('Information (bits)');
end
else
% We're on Matlab - just make a quick plot
plot(deltas, mitXnToYnplus1, 'rx', 'markersize', markersize); % Empirical: MIT(X \rightarrow Y, 1)
hold on;
plot(deltas, mitXnToYnplus1_an, 'rp', 'markersize', markersize); % Analytic: MIT(X \rightarrow Y, 1)
plot(deltas, mitXnminus1ToYnplus1, 'g+', 'markersize', markersize); % Empirical: MIT(X \rightarrow Y, 2)
plot(deltas, mitXnminus1ToYnplus1_an, 'go', 'markersize', markersize); % Analytic: MIT(X \rightarrow Y, 2)
hold off;
% Make figures ok for plotting:
legend('Empirical: MIT(X \rightarrow Y, 1)', 'Analytic: MIT(X \rightarrow Y, 1)', ...
'Empirical: MIT(X \rightarrow Y, 2)', 'Analytic: MIT(X \rightarrow Y, 2)', ...
'Location', 'East');
end
toc;
end