From aedefd07bc46878e928ef702040cf3ec14fb228c Mon Sep 17 00:00:00 2001 From: jlizier Date: Mon, 22 May 2017 15:53:42 +1000 Subject: [PATCH] Fixed analytic expressions for transfer entropies in the simple demos for coupled Gaussians (should have computed directly from the empirical correlations all along, but didn't notice because errors were very small) --- .../clojure/examples/example3TeContinuousDataKernel.clj | 1 + .../clojure/examples/example4TeContinuousDataKraskov.clj | 1 + .../demos/Example3TeContinuousDataKernel.java | 9 +++++++-- .../demos/Example4TeContinuousDataKraskov.java | 7 ++++++- demos/julia/example3TeContinuousDataKernel.jl | 8 ++++++-- demos/julia/example4TeContinuousDataKraskov.jl | 6 +++++- demos/octave/example3TeContinuousDataKernel.m | 8 ++++++-- demos/octave/example4TeContinuousDataKraskov.m | 6 +++++- demos/python/example3TeContinuousDataKernel.py | 8 ++++++-- demos/python/example4TeContinuousDataKraskov.py | 6 +++++- demos/r/example3TeContinuousDataKernel.r | 8 ++++++-- demos/r/example4TeContinuousDataKraskov.r | 6 +++++- 12 files changed, 59 insertions(+), 15 deletions(-) diff --git a/demos/clojure/examples/example3TeContinuousDataKernel.clj b/demos/clojure/examples/example3TeContinuousDataKernel.clj index ea6d63a..1dc5af2 100755 --- a/demos/clojure/examples/example3TeContinuousDataKernel.clj +++ b/demos/clojure/examples/example3TeContinuousDataKernel.clj @@ -45,6 +45,7 @@ (.setObservations teCalc sourceArray destArray) ; For copied source, should give something close to expected value for correlated Gaussians: +; TODO The analytic result quoted here isn't quite right, see e.g. octave demos (can't be bothered fixing here...) (println "TE result " (.computeAverageLocalOfObservations teCalc) " expected to be close to " (/ (Math/log (/ 1 (- 1 (* covariance covariance)))) (Math/log 2)) " for these correlated Gaussians but biased upward") diff --git a/demos/clojure/examples/example4TeContinuousDataKraskov.clj b/demos/clojure/examples/example4TeContinuousDataKraskov.clj index bb63fe7..1c04be0 100755 --- a/demos/clojure/examples/example4TeContinuousDataKraskov.clj +++ b/demos/clojure/examples/example4TeContinuousDataKraskov.clj @@ -49,6 +49,7 @@ ; data is a set of random variables) - the result will be of the order ; of what we expect, but not exactly equal to it; in fact, there will ; be a large variance around it. +; TODO The analytic result quoted here isn't quite right, see e.g. octave demos (can't be bothered fixing here...) (println "TE result " (.computeAverageLocalOfObservations teCalc) " nats expected to be close to " (Math/log (/ 1 (- 1 (* covariance covariance)))) " nats for these correlated Gaussians") diff --git a/demos/java/infodynamics/demos/Example3TeContinuousDataKernel.java b/demos/java/infodynamics/demos/Example3TeContinuousDataKernel.java index c65595b..4775f83 100755 --- a/demos/java/infodynamics/demos/Example3TeContinuousDataKernel.java +++ b/demos/java/infodynamics/demos/Example3TeContinuousDataKernel.java @@ -58,11 +58,16 @@ public class Example3TeContinuousDataKernel { teCalc.setProperty("NORMALISE", "true"); // Normalise the individual variables (default) teCalc.initialise(1, 0.5); // Use history length 1 (Schreiber k=1), kernel width of 0.5 normalised units teCalc.setObservations(sourceArray, destArray); - // For copied source, should give something close to expected value for correlated Gaussians: double result = teCalc.computeAverageLocalOfObservations(); + // For copied source, should give something close to expected value for correlated Gaussians:. + // Expected correlation is expected covariance / product of expected standard deviations: + // (where square of destArray standard dev is sum of squares of std devs of + // underlying distributions) + double corr_expected = covariance / + (1.0 * Math.sqrt(Math.pow(covariance,2) + Math.pow(1-covariance,2))); System.out.printf("TE result %.4f bits; expected to be close to " + "%.4f bits for these correlated Gaussians but biased upwards\n", - result, Math.log(1.0/(1-Math.pow(covariance,2)))/Math.log(2)); + result, -0.5 * Math.log(1-Math.pow(corr_expected,2))/Math.log(2)); teCalc.initialise(); // Initialise leaving the parameters the same teCalc.setObservations(sourceArray2, destArray); diff --git a/demos/java/infodynamics/demos/Example4TeContinuousDataKraskov.java b/demos/java/infodynamics/demos/Example4TeContinuousDataKraskov.java index ccbc221..a1276d4 100755 --- a/demos/java/infodynamics/demos/Example4TeContinuousDataKraskov.java +++ b/demos/java/infodynamics/demos/Example4TeContinuousDataKraskov.java @@ -65,9 +65,14 @@ public class Example4TeContinuousDataKraskov { // data is a set of random variables) - the result will be of the order // of what we expect, but not exactly equal to it; in fact, there will // be a large variance around it. + // Expected correlation is expected covariance / product of expected standard deviations: + // (where square of destArray standard dev is sum of squares of std devs of + // underlying distributions) + double corr_expected = covariance / + (1.0 * Math.sqrt(Math.pow(covariance,2) + Math.pow(1-covariance,2))); System.out.printf("TE result %.4f nats; expected to be close to " + "%.4f nats for these correlated Gaussians\n", - result, Math.log(1.0/(1-Math.pow(covariance,2)))); + result, -0.5 * Math.log(1-Math.pow(corr_expected,2))); // Perform calculation with uncorrelated source: teCalc.initialise(); // Initialise leaving the parameters the same diff --git a/demos/julia/example3TeContinuousDataKernel.jl b/demos/julia/example3TeContinuousDataKernel.jl index 2a9572a..ee3f115 100755 --- a/demos/julia/example3TeContinuousDataKernel.jl +++ b/demos/julia/example3TeContinuousDataKernel.jl @@ -42,9 +42,13 @@ jcall(teCalc, "setProperty", Void, (JString, JString), "NORMALISE", "true"); # N jcall(teCalc, "initialise", Void, (jint, jdouble), 1, 0.5); # Use history length 1 (Schreiber k=1), kernel width of 0.5 normalised units jcall(teCalc, "setObservations", Void, (Array{jdouble,1}, Array{jdouble,1}), sourceArray, destArray); -# For copied source, should give something close to expected value for correlated Gaussians: result = jcall(teCalc, "computeAverageLocalOfObservations", jdouble, ()); -@printf("TE result %.4f bits; expected to be close to %.4f bits for these correlated Gaussians but biased upwards\n", result, log(1/(1-covariance^2))/log(2)); +# For copied source, should give something close to expected value for correlated Gaussians: +# Expected correlation is expected covariance / product of expected standard deviations: +# (where square of destArray standard dev is sum of squares of std devs of +# underlying distributions) +corr_expected = covariance / (1 * sqrt(covariance^2 + (1-covariance)^2)); +@printf("TE result %.4f bits; expected to be close to %.4f bits for these correlated Gaussians but biased upwards\n", result, -0.5*log(1-corr_expected^2)/log(2)); jcall(teCalc, "initialise", Void, ()); # Initialise leaving the parameters the same jcall(teCalc, "setObservations", Void, (Array{jdouble,1}, Array{jdouble,1}), diff --git a/demos/julia/example4TeContinuousDataKraskov.jl b/demos/julia/example4TeContinuousDataKraskov.jl index 1a58930..a69dc7f 100755 --- a/demos/julia/example4TeContinuousDataKraskov.jl +++ b/demos/julia/example4TeContinuousDataKraskov.jl @@ -49,8 +49,12 @@ result = jcall(teCalc, "computeAverageLocalOfObservations", jdouble, ()); # data is a set of random variables) - the result will be of the order # of what we expect, but not exactly equal to it; in fact, there will # be a large variance around it. +# Expected correlation is expected covariance / product of expected standard deviations: +# (where square of destArray standard dev is sum of squares of std devs of +# underlying distributions) +corr_expected = covariance / (1 * sqrt(covariance^2 + (1-covariance)^2)); @printf("TE result %.4f nats; expected to be close to %.4f nats for these correlated Gaussians\n", - result, log(1/(1-covariance^2))); + result, -0.5*log(1-corr_expected^2)); # Perform calculation with uncorrelated source: jcall(teCalc, "initialise", Void, ()); # Initialise leaving the parameters the same diff --git a/demos/octave/example3TeContinuousDataKernel.m b/demos/octave/example3TeContinuousDataKernel.m index 594cf39..212af5a 100755 --- a/demos/octave/example3TeContinuousDataKernel.m +++ b/demos/octave/example3TeContinuousDataKernel.m @@ -34,10 +34,14 @@ teCalc=javaObject('infodynamics.measures.continuous.kernel.TransferEntropyCalcul teCalc.setProperty('NORMALISE', 'true'); % Normalise the individual variables teCalc.initialise(1, 0.5); % Use history length 1 (Schreiber k=1), kernel width of 0.5 normalised units teCalc.setObservations(sourceArray, destArray); -% For copied source, should give something close to expected value for correlated Gaussians: result = teCalc.computeAverageLocalOfObservations(); +% For copied source, should give something close to expected value for correlated Gaussians. +% Expected correlation is expected covariance / product of expected standard deviations: +% (where square of destArray standard dev is sum of squares of std devs of +% underlying distributions) +corr_expected = covariance ./ (1 * sqrt(covariance^2 + (1-covariance)^2)); fprintf('TE result %.4f bits; expected to be close to %.4f bits for these correlated Gaussians but biased upwards\n', ... - result, log(1/(1-covariance^2))/log(2)); + result, -0.5*log(1-corr_expected^2)/log(2)); teCalc.initialise(); % Initialise leaving the parameters the same teCalc.setObservations(sourceArray2, destArray); % For random source, it should give something close to 0 bits diff --git a/demos/octave/example4TeContinuousDataKraskov.m b/demos/octave/example4TeContinuousDataKraskov.m index 7d353c9..5e43395 100755 --- a/demos/octave/example4TeContinuousDataKraskov.m +++ b/demos/octave/example4TeContinuousDataKraskov.m @@ -40,8 +40,12 @@ result = teCalc.computeAverageLocalOfObservations(); % data is a set of random variables) - the result will be of the order % of what we expect, but not exactly equal to it; in fact, there will % be a large variance around it. +% Expected correlation is expected covariance / product of expected standard deviations: +% (where square of destArray standard dev is sum of squares of std devs of +% underlying distributions) +corr_expected = covariance ./ (1 * sqrt(covariance^2 + (1-covariance)^2)); fprintf('TE result %.4f nats; expected to be close to %.4f nats for these correlated Gaussians\n', ... - result, log(1/(1-covariance^2))); + result, - 0.5 * log(1-corr_expected^2)); % Perform calculation with uncorrelated source: teCalc.initialise(); % Initialise leaving the parameters the same teCalc.setObservations(sourceArray2, destArray); diff --git a/demos/python/example3TeContinuousDataKernel.py b/demos/python/example3TeContinuousDataKernel.py index f29b027..bf7f0e6 100755 --- a/demos/python/example3TeContinuousDataKernel.py +++ b/demos/python/example3TeContinuousDataKernel.py @@ -45,10 +45,14 @@ teCalc = teCalcClass() teCalc.setProperty("NORMALISE", "true") # Normalise the individual variables teCalc.initialise(1, 0.5) # Use history length 1 (Schreiber k=1), kernel width of 0.5 normalised units teCalc.setObservations(JArray(JDouble, 1)(sourceArray), JArray(JDouble, 1)(destArray)) -# For copied source, should give something close to 1 bit: result = teCalc.computeAverageLocalOfObservations() +# For copied source, should give something close to 1 bit: +# Expected correlation is expected covariance / product of expected standard deviations: +# (where square of destArray standard dev is sum of squares of std devs of +# underlying distributions) +corr_expected = covariance / (1 * math.sqrt(covariance**2 + (1-covariance)**2)); print("TE result %.4f bits; expected to be close to %.4f bits for these correlated Gaussians but biased upwards" % \ - (result, math.log(1/(1-math.pow(covariance,2)))/math.log(2))) + (result, -0.5*math.log(1-math.pow(corr_expected,2))/math.log(2))) teCalc.initialise() # Initialise leaving the parameters the same teCalc.setObservations(JArray(JDouble, 1)(sourceArray2), JArray(JDouble, 1)(destArray)) # For random source, it should give something close to 0 bits diff --git a/demos/python/example4TeContinuousDataKraskov.py b/demos/python/example4TeContinuousDataKraskov.py index ac65bab..6f9132b 100755 --- a/demos/python/example4TeContinuousDataKraskov.py +++ b/demos/python/example4TeContinuousDataKraskov.py @@ -52,8 +52,12 @@ result = teCalc.computeAverageLocalOfObservations() # data is a set of random variables) - the result will be of the order # of what we expect, but not exactly equal to it; in fact, there will # be a large variance around it. +# Expected correlation is expected covariance / product of expected standard deviations: +# (where square of destArray standard dev is sum of squares of std devs of +# underlying distributions) +corr_expected = covariance / (1 * math.sqrt(covariance**2 + (1-covariance)**2)); print("TE result %.4f nats; expected to be close to %.4f nats for these correlated Gaussians" % \ - (result, math.log(1/(1-math.pow(covariance,2))))) + (result, -0.5 * math.log(1-corr_expected**2))) # Perform calculation with uncorrelated source: teCalc.initialise() # Initialise leaving the parameters the same teCalc.setObservations(JArray(JDouble, 1)(sourceArray2), JArray(JDouble, 1)(destArray)) diff --git a/demos/r/example3TeContinuousDataKernel.r b/demos/r/example3TeContinuousDataKernel.r index 44e557b..47e7393 100755 --- a/demos/r/example3TeContinuousDataKernel.r +++ b/demos/r/example3TeContinuousDataKernel.r @@ -41,9 +41,13 @@ teCalc<-.jnew("infodynamics/measures/continuous/kernel/TransferEntropyCalculator .jcall(teCalc,"V","setProperty", "NORMALISE", "true") # Normalise the individual variables .jcall(teCalc,"V","initialise", 1L, 0.5) # Use history length 1 (Schreiber k=1), kernel width of 0.5 normalised units .jcall(teCalc,"V","setObservations", sourceArray, destArray) -# For copied source, should give something close to expected value for correlated Gaussians: result <- .jcall(teCalc,"D","computeAverageLocalOfObservations") -cat("TE result ", result, "bits; expected to be close to ", log(1/(1-covariance^2))/log(2), " bits for these correlated Gaussians but biased upwards\n") +# For copied source, should give something close to expected value for correlated Gaussians. +# Expected correlation is expected covariance / product of expected standard deviations: +# (where square of destArray standard dev is sum of squares of std devs of +# underlying distributions) +corr_expected <- covariance / (1 * sqrt(covariance^2 + (1-covariance)^2)); +cat("TE result ", result, "bits; expected to be close to ", -0.5*log(1-corr_expected^2)/log(2), " bits for these correlated Gaussians but biased upwards\n") .jcall(teCalc,"V","initialise") # Initialise leaving the parameters the same .jcall(teCalc,"V","setObservations", sourceArray2, destArray) diff --git a/demos/r/example4TeContinuousDataKraskov.r b/demos/r/example4TeContinuousDataKraskov.r index d2ea19c..3bdb982 100755 --- a/demos/r/example4TeContinuousDataKraskov.r +++ b/demos/r/example4TeContinuousDataKraskov.r @@ -48,7 +48,11 @@ result <- .jcall(teCalc,"D","computeAverageLocalOfObservations") # data is a set of random variables) - the result will be of the order # of what we expect, but not exactly equal to it; in fact, there will # be a large variance around it. -cat("TE result ", result, "nats; expected to be close to ", log(1/(1-covariance^2)), " nats for these correlated Gaussians\n") +# Expected correlation is expected covariance / product of expected standard deviations: +# (where square of destArray standard dev is sum of squares of std devs of +# underlying distributions) +corr_expected <- covariance / (1 * sqrt(covariance^2 + (1-covariance)^2)); +cat("TE result ", result, "nats; expected to be close to ", -0.5*log(1-corr_expected^2), " nats for these correlated Gaussians\n") # Perform calculation with uncorrelated source: .jcall(teCalc,"V","initialise") # Initialise leaving the parameters the same