Compare commits

...

295 Commits
v1.4 ... master

Author SHA1 Message Date
Joseph Lizier fea2cb4bfa Targeting Java version 8 in our builds now, in part to be compatible with latest Jpype in python 2025-10-16 09:17:00 +11:00
Joseph Lizier cb12914e7a Changing spiking TE code to return all embeddings with the local TE contributions at each spike 2025-05-02 16:06:52 +10:00
Joseph Lizier d773508cf9 Fixing handling of data normalisation in the KNN computation methods 2025-04-01 23:09:09 +11:00
Joseph Lizier 333a00fc07 Adding method to compute kNN distances for KSG AIS estimator 2025-04-01 22:55:28 +11:00
Joseph Lizier 2ab3ec347c Adding method for KSG TE estimator to return KNN distances 2025-04-01 22:49:45 +11:00
Joseph Lizier 5dc9d00aff Adding univariate calls for KNN distances in KSG MI estimators 2025-04-01 22:33:45 +11:00
Joseph Lizier c08aeb1783 Adding univariate calls for cross CMI 2025-04-01 22:33:02 +11:00
Joseph Lizier fa21f7343a Adding debug methods to KSG estimators to retrieve knn distances 2025-04-01 18:08:38 +11:00
Joseph Lizier 13251a0104 Cleaning up code of the spiking TE estimator 2025-04-01 15:29:20 +11:00
Joseph Lizier 283dcb3b94 Adding a field to the object returned from local TE for spike trains which holds the ISI to previous (selected) source spike 2025-03-28 18:09:28 +11:00
Joseph Lizier cab3de8b07 Bug fix to local TE for spike trains code; forgot to increment the index when computing local values, fixed. 2025-03-28 15:15:30 +11:00
Joseph Lizier efd3943697 Implementing local TE contributions for the spiking estimator 2025-03-21 16:08:39 +11:00
Joseph Lizier 912bdf94e1 Flocking demo: comments added to properties file on how to handle individuals not being present at any given time step. 2024-11-04 12:21:22 +11:00
Joseph Lizier 5d4419d734 Batch file to setup a python virtual environment 2024-07-19 13:54:24 +10:00
Joseph Lizier a9b6b3e77c Adding property to set random seed for noise addition to EntropyMultiVariate estimators (mimicing that for MI/CMI estimators), extending the fix for issue #99 to Entropy estimators 2024-04-20 18:52:10 +10:00
Joseph Lizier 3d1f3fec86 Gathering common functionality of EntropyMultiVariate estimators into a Common class. Adds some new functionality (e.g. addObservations() for Gaussian and Kernel) 2024-04-20 17:57:38 +10:00
Joseph Lizier 2a18cd0e74 Adding property to allow used to set random seed for noise addition to data in MI, CMI and wrapped estimators. Closes issue #99 2024-04-16 14:08:04 +10:00
Joseph Lizier 2130985c34 Adding/implementing interfaces for continuous CMI estimators to allow all combinations of univariate/multivariate arrays to be passed for var1/var2/conditional 2023-10-27 10:04:25 +11:00
Joseph Lizier 7d8b501127 Adding new unit test for dynamic correlation exclusion, testing both an analytic result, and also the effect of using seperate observation sets 2023-10-10 22:38:21 +11:00
Joseph Lizier 4b85a7fd46 AIS and TE estimators (for KSG in particular) utilising the underlying NN Searchers holding the different data sets separately. 2023-10-09 13:16:27 +11:00
Joseph Lizier ec8e7f848f CMI common estimators utilising underlying nearest neighbour searchers holding different data sets separately (for dynamic correlation exclusion) 2023-10-09 13:15:56 +11:00
Joseph Lizier 5f87e2018b MI common estimators utilising underlying nearest neighbour searchers holding different data sets separately (for dynamic correlation exclusion) 2023-10-09 13:14:29 +11:00
Joseph Lizier 938dd7c4fb Implementing multiple data sets in the nearest neighbour searches, to facilitate dynamic correlation exclusion only for points within the same data set 2023-10-09 13:12:07 +11:00
Joseph Lizier a554361de9 Adding unit test for no conditional on CMI Gaussian 2023-10-06 12:29:37 +11:00
Joseph Lizier 4f5d8f894b Updating documentation to v1.6.1 minor release 2023-08-22 13:02:19 +10:00
Joseph Lizier 90baf68ee7 Making AutoAnalyser Python code only start JVM if not already started 2023-08-21 17:55:16 +10:00
Joseph Lizier 817abd1de0 For Autoanalyser Python code adding \ at the end of line for print statement 2023-08-15 16:28:04 +10:00
Joseph Lizier f643632df4 Adding AutoAnalyser launcher in python 2023-08-11 18:03:28 +10:00
Joseph Lizier f55737c650 Further refinements to python environment start code 2023-07-26 15:02:58 +10:00
Joseph Lizier 107fabad32 Small fixed to spiking TE demo (sent from David) 2023-07-26 14:52:03 +10:00
Joseph Lizier d920b1e9a9 Minor tweaks to Flocking analysis demo 2023-07-26 14:48:55 +10:00
Joseph Lizier 23bfeded27 Updating python environment scripts, and adding one to start jupyter in the environment 2023-07-26 14:46:51 +10:00
Joseph Lizier 40d51ed542
Merge pull request #95 from dpshorten/master
sensible parameter choices for SpikeTrainTETesting.py
2023-02-20 11:36:26 +01:00
David Shorten 0cef502948 sensible parameter choices for SpikeTrainTETesting.py 2023-02-20 12:54:16 +10:30
jlizier 28954585f4 Updated a file loader for Flocking demo 2022-09-08 16:14:53 +10:00
jlizier 26e3cd8afb Supporting AIS only calculation in flocking demo 2022-09-08 11:27:27 +10:00
jlizier 6dc6b8fa11 Merge branch 'master' of github.com:jlizier/jidt 2022-09-08 10:26:59 +10:00
jlizier 865d82630a Altering AutoAnalyser generated python code to set flag convertStrings=True in JVM start, as per PR #94 2022-09-08 10:20:20 +10:00
jlizier ee3ce5dd51 Corrected function signature in loadxls2d for fish data loading 2022-09-07 09:17:51 +10:00
jlizier 8bc6d87d9b Adding scripts to create and start a python virtual environment with jpype1 etc installed 2022-09-06 10:27:38 +10:00
jlizier 348587ee59 Python demo 1 - removing deprecated type call in script 2022-09-06 10:27:08 +10:00
Joseph Lizier 8c001e6ddd
Updated links for v1.6 release 2022-09-06 00:02:37 +10:00
jlizier 65aa685d11 Fixing python demo 6, where the multivariate array conversion wasn't working for Python3 with Jpype. Fixed to use recommended array conversion as per UseInPython wiki. Addresses issue raised in PR #87 also. 2022-09-05 23:13:52 +10:00
jlizier 2b0a5cb943 Updated mixed-continiuous CMI KSG estimator, for the bias correction based on number of continuous variables. This was identified from testing, and aligns with testing so far. 2022-09-05 17:51:49 +10:00
jlizier 72024c7299 Updating demo PDFs and version number ahead of new v1.6 distribution 2022-09-05 17:43:14 +10:00
Joseph Lizier d750a737be
Removing what appears to be an old test file from the integrated Spiking TE code from David 2022-09-05 17:08:10 +10:00
jlizier 003a187a7a moving the demos using spiking TE estimator into different folder locations 2022-09-05 15:00:05 +10:00
Joseph Lizier fcfcca962b
Adding David Shorten to the authors list 2022-09-05 14:54:30 +10:00
Joseph Lizier 27f9cccf65
Don't need code for old way of doing spiking TE estimation 2022-09-05 14:45:50 +10:00
Joseph Lizier 47be5df74b
editing comment on how to implement dynamic correlation exclusions in spiking TE estimator 2022-09-05 14:43:18 +10:00
Joseph Lizier e747e8aa93
Merge pull request #93 from dpshorten/master
Spike train TE estimation
2022-09-05 14:38:21 +10:00
Joseph Lizier 8db0c12c37
Brief update to header comments on spiking TE example 2022-09-05 14:32:14 +10:00
jlizier 05248ef105 Extra fixing windows paths generated from AutoAnalyser to be properly escaped in data filename for Python/Matlab 2022-09-01 15:50:27 +10:00
jlizier c233485c90 Fixing windows paths generated from AutoAnalyser to be properly escaped 2022-09-01 15:28:28 +10:00
jlizier 9c2a25492f Clarifying where Econometrics Toolbox is required for Flocking demo 2022-08-30 12:38:10 +10:00
jlizier 5398785a67 Adding comment to Flocking demo that Econometrics Toolbox may be required 2022-08-30 12:37:03 +10:00
jlizier d250c6b24c Updating error comment in Flocking demo 2022-08-30 12:33:55 +10:00
dpshorten dc3874c72b
Update net_inf.py
Comments to the net_inf.py file.
2022-08-25 16:12:35 +09:30
Joseph Lizier a040cde6da
Adding header comment to spk_to_pk.py and changing filename 2022-08-25 15:24:51 +10:00
jlizier 0935806338 Moving ant targets up to Java 7 instead of Java 6 (newer java versions are complaining now that 6 is too old to target) 2022-08-16 15:50:17 +10:00
David Shorten bcefd900c4 moved the location of the Python testing script 2022-08-04 16:06:25 +09:30
David Shorten a398c925a8 added python for spiking network inference 2022-08-04 16:03:12 +09:30
jlizier 9dfafda555 Merge branch 'master' of github.com:jlizier/jidt 2022-06-16 21:33:41 +10:00
jlizier 2714650cfa Amending Kraskov (KSG) MI estimators to have an experimental method to provide conditional entropy of the first variable given the second. Works by removing the Kozachenko Leonenko entropy of variable 1 from the MI, using the same kNN radii as the MI estimator. Includes Unit tests to provide some initial validation. 2022-06-16 21:29:29 +10:00
Joseph Lizier 2c72eb05f9
Specified AntScripts for quick build 2022-06-14 09:54:49 +10:00
jlizier 25159009ca updating max entropy discretisation to gracefully handle NaNs in the input (which shouldn't be there anyway) 2022-06-09 12:39:59 +10:00
Joseph Lizier e9fc39c4c2 Added simple Matlab script implementing the muiltivariate/iterative/greedy algorithm for effective network inference. Is a simplified version of the full algorithm in IDTxl, for demonstration purposes. Also includes calls to Oliver Cliff's toolkit for granger causality, which won't be functional for users who have not downloaded that; will be removed when the autocorrelation correction is added to JIDT for linear. 2022-04-08 10:49:57 +10:00
Joseph Lizier 899a5607f8 Merge branch 'master' of github.com:jlizier/JIDT 2022-03-31 12:16:21 +11:00
Joseph Lizier 41361417ae Updates to flocking demo including plotting local TEs per individual per time frame 2022-03-31 12:14:16 +11:00
David Shorten c068c8308d improving jittered surrogates 2022-02-25 18:49:12 +11:00
David Shorten 285c95947a integrating artemis changes 2022-02-22 14:39:15 +11:00
David Shorten b4e32727c9 merge 2022-02-22 11:55:09 +11:00
Joseph Lizier 0e33393cdc
Merge pull request #86 from pmediano/master
Thanks Pedro, and sorry to take so long to attend to this
2021-11-15 12:08:57 +11:00
Joseph Lizier b02760ddd3 Adding overloads on setObservations and addObservations for MI and TE calculators to handle one variable univariate and one variable multivariate 2021-11-15 10:58:59 +11:00
Joseph Lizier 8e55cf05d9 Merge branch 'master' of github.com:jlizier/JIDT 2021-11-02 23:13:59 +11:00
Joseph Lizier 7d7291fb9d Implementing Analytic null distributions for discrete conditional TE estimator 2021-11-02 23:11:45 +11:00
Joseph Lizier e5b223606c
Added YouTube image and link to Course to README 2021-10-11 23:12:39 +11:00
Joseph Lizier a65db51b78 Merge branch 'master' of github.com:jlizier/JIDT 2021-10-11 23:07:07 +11:00
Joseph Lizier 9c31807283 Adding image for the YouTube playlist 2021-10-11 23:05:53 +11:00
Joseph Lizier b4ab18f6c6
Adding link to Course to repo home page 2021-10-11 15:40:10 +11:00
Joseph Lizier 6f43dfb620 Altering the python-java jpype data conversion in AutoAnalyser to work properly with jpype 0.7 and upwards 2021-10-08 16:03:14 +11:00
Joseph Lizier f8eb84e183 Merge branch 'master' of github.com:jlizier/JIDT 2021-10-08 11:30:54 +11:00
Joseph Lizier 21ae0bdeaa Fixing logic error in printing whether GPU calculation was falling back to CPU 2021-10-08 11:28:37 +11:00
Joseph Lizier d101a9f2ff
Update README.md 2021-10-01 17:33:24 +10:00
Joseph Lizier ccf920d3a8
Added readme file to course folder 2021-10-01 17:32:21 +10:00
Joseph Lizier 898a04904c Added Matlab script to launch the AutoAnalyser - will be useful for Matlab users who don't have a separate JRE installed 2021-09-09 11:12:46 +10:00
Joseph Lizier 2caab8593e Adding option for generated CA cells to be stochastically altered in CA utility code 2021-09-06 12:51:14 +10:00
Joseph Lizier 5da70db3ae Updating readme pdfs for various demos from the JIDT wiki 2021-09-06 12:49:50 +10:00
Joseph Lizier 650159661d Patching conditional MI calculator to properly allow null or empty conditionals if dimension of conditionals is 0 2021-09-06 10:23:31 +10:00
David Shorten c8d17e9522 functionality allowing specific embedding intervals 2021-08-23 17:50:34 +10:00
Joseph Lizier aa8148eca9 Updates to KL entropy estimator: removing NORMALISE property, and adding method for cross entropy 2021-08-23 09:09:49 +10:00
David Shorten dd215fdfbb spiking surrogates implemented 2021-08-11 09:20:35 +10:00
Joseph Lizier ef7cfbb525 Fixed missing " in comment 2021-08-06 17:43:56 +10:00
David Shorten dc85001ff7 refactoring + conditional processes + radius sharing + euclidean norm working 2021-08-02 22:06:07 +10:00
David Shorten 9a17361cca minor edits 2021-07-26 21:34:22 +10:00
David Shorten dc226be60a minor refactorings 2021-07-25 17:47:27 +10:00
David Shorten 8d7c598022 better testing script and a touch of refactoring 2021-07-25 17:30:30 +10:00
David Shorten cf5f8edf5e confirmed working on canonical ex 2021-07-25 16:29:31 +10:00
David Shorten 4ece80b5ef appear to have 4kl estimator working 2021-07-24 23:32:57 +10:00
David Shorten bb51b09048 converting embedding vectors to arrays for the trees 2021-07-23 17:54:46 +10:00
David Shorten 0e530cdceb history embeddings done 2021-07-23 17:26:18 +10:00
David Shorten deb9d97520 advancing previous indices throughout iteration 2021-07-22 19:06:53 +10:00
David Shorten fe0fb2ed49 positioning embeddings start point 2021-07-22 17:55:00 +10:00
David Shorten 56dacc5232 some progress towards PCB spiking estimator 2021-07-22 14:19:36 +10:00
David Shorten 4f889df786 added testing script 2021-07-21 10:15:08 +10:00
Joseph Lizier 70a7f5c33a Clarifying how to access an attribute (pValue) in the R demos 2021-04-19 11:32:23 +10:00
Pedro Mediano 07883af734 Updated printed messages with cross-platform newline character. 2021-02-09 10:23:30 +00:00
Pedro Mediano bc8c233e68 Added KSG implementation of various multivariate IT measures and unit tests. 2021-01-25 12:41:01 +00:00
Pedro Mediano a58a01fbfd Added discrete implementation of various multivariate IT measures and unit tests. 2021-01-24 22:13:15 +00:00
Pedro Mediano b3abd382aa Added abstract parent class for multivariate IT measures on discrete data. 2021-01-24 22:10:14 +00:00
Pedro Mediano f67e274819 Added Gaussian implementation of various multivariate IT measures and unit tests. 2021-01-24 22:06:39 +00:00
Pedro Mediano 403745800e Added abstract parent class for multivariate IT measures on continuous data. 2021-01-24 21:56:26 +00:00
Pedro Mediano 06cc6d649d Added `select*` methods for `int[][]` matrices. 2021-01-24 21:54:42 +00:00
Pedro Mediano b3192e225f Added convenience methods to multiply an array times a constant value. 2021-01-24 21:54:09 +00:00
Joseph Lizier 3222b5a629 Implementation and unit test for KSG MI calculation with new samples (both algorithms 1 and 2) 2020-10-30 16:21:10 +11:00
Joseph Lizier 0606f8ab39 Cleaning up CMI Kraskov for new samples, including fixing some comments, logic of not using GPU for this, and if no conditional counting all point as a conditional match 2020-10-30 16:19:31 +11:00
Joseph Lizier b5a6fa92c2 Fixing min and max of local CMI values 2020-10-29 13:45:25 +11:00
Joseph Lizier 44e53bc846 Updating error messages for kdTree 2020-10-29 13:39:40 +11:00
Joseph Lizier 8ecb512ce0 Updating flocking analysis to save AIS/TE from all parameters tested in an autoembedding process 2020-09-03 22:20:03 +10:00
Joseph Lizier 4c95b4ee86 Updating Flocking analysis demo to have more aggressive dynamic correlation exclusion. Also adding utility to plot the raw positions of the floc 2020-09-01 11:22:31 +10:00
Joseph Lizier 34161a2e6d Adding non-overloaded method signatures for multivariate arrays, so that the jpype python-java bridge can resolve which method signature to use more directly via these 2020-05-22 14:42:26 +10:00
Joseph Lizier bf207f866e Patched error in computing start and end times for valid observation sequences in conditional TE calculators (with validity booleans) 2020-05-21 00:57:34 +10:00
Joseph Lizier 820f700cb8 Fixed python write file utilities to work with unidimensional arrays 2020-05-21 00:19:16 +10:00
Joseph Lizier 471ea59bb2 Adding utilities for writing text files in python (can be done with numpy, but just making something quick my way) 2020-05-20 23:46:55 +10:00
Joseph Lizier d0a0fca40c Added non-overloaded method calls for conditionalTE continuous' addObservations() method calls with validity booleans - this is for JPype from Python which seems unable to resolve overloads of double[] and double[][], when more than one variable changes in this way 2020-05-16 12:18:57 +10:00
Joseph Lizier ccbccc6302 Merge branch 'master' of github.com:jlizier/JIDT 2020-05-15 17:37:32 +10:00
Joseph Lizier cbcca8d0ff fixing addedMoreThanOneObservationSet for the MultiInfoCalculator 2020-05-15 17:35:54 +10:00
Joseph Lizier 510f999d2e Adds addObservations calls with validity arrays for conditional transfer entropy 2020-05-15 17:34:00 +10:00
Pedro Mediano 64a7a80e30
Changed name of LDFLAGS to avoid potential conflicts
Closes #80 .
2020-05-02 14:37:27 +01:00
Joseph Lizier 1c2ccda1eb
Updated contributors list 2020-01-24 11:42:56 +11:00
Joseph Lizier edb8f997cb Added new loader file for 2D xls format to flocking analysis demo 2019-12-17 17:08:27 +11:00
Joseph Lizier 502f7ac22c Merge branch 'master' of github.com:jlizier/JIDT 2019-12-13 11:44:03 +11:00
Joseph Lizier 2c2d012e20 Sooraj Sekhar's addition to flocking analysis of allowing speed to be included in the information-theoretic calculations. Includes updated NetLogo demo where speed coherence is also added 2019-12-13 11:40:58 +11:00
Joseph Lizier f53ecba635
Added Emanuele Crosato to author's list for the flocking demo code 2019-09-01 22:06:27 +10:00
Joseph Lizier 4966fdabc2 Adding a code suite to run active information storage and transfer entropy analysis of positional / heading data from swarms/flocks/schools, including a demonstration of how to use the suite with a NetLogo example. Documentation on a wiki page to follow later ... 2019-08-29 23:08:16 +10:00
Joseph Lizier c22e37d1ab Adding new lecture slides for Module 0 Introduction to course 2019-08-09 17:20:12 +10:00
Joseph Lizier 61ae6fb40b Minor updates to AutoAnalyser to put fixtures in place for array conversion to Python with eventual handling of 2D arrays (code isn't really changed at the moment, but has methods to make this easy later) 2019-07-25 23:56:56 +10:00
Joseph Lizier 2ab3ac01bb Adding non-overloaded method signatures for adding 1D vs 2D observations for common class for continuous MI and CMI estimators, since JPype 0.7 does not seem able to resolve overloaded 1D vs 2D arrays any longer 2019-07-25 23:11:44 +10:00
Joseph Lizier 1667b9fe7a Added utility for subsampling rows from 2D matrix 2019-07-25 14:36:54 +10:00
Joseph Lizier 1dc2dc8b86 Updating all discrete calculators (except SeparableInfo, since it's outmoded) to have a default empty constructor, with an overloaded initialise method added that provides all relevant properties. Fixes #77, and provides a first step for #66. Also aligned PredictiveInfo and ConditionalTE calculators to use the appropriate super classes. 2019-07-25 14:29:51 +10:00
Joseph Lizier d545793bc5 Patching unit test on KSG MI with discrete which tested that result changed from K=2 to 4, but the threshold for change was too large. 2019-07-25 10:14:57 +10:00
Joseph Lizier 0dae162d82 Added new unit tests for TE with k=0 for Gaussian and KSG estimators 2019-07-23 11:43:55 +10:00
Joseph Lizier 17bf0e0be7 Updating octave-java interface to use non-overloaded method signatures for int and boolean arrays (this seemed to have caused an issue on some versions with ints being converted to boolean first, thus losing all values except 0-1) 2019-07-23 11:33:04 +10:00
Joseph Lizier fba941362d Adding further unit tests for Conditional TE (continuous-valued) to check different delays on conditional variables, and patching test of validity of calling univariate versus multivariate method signatures. 2019-07-12 14:45:23 +10:00
Joseph Lizier 1db8a2ac63 Making local computation for CMI Gaussian calculator store the lastAverage if it was called with the previous observations 2019-05-17 22:47:16 +10:00
Joseph Lizier 681c9196ee Added methods to MatrixUtils (plus unit tests) for adding/removing/swapping sample points into existing means and covariances 2019-05-17 22:27:30 +10:00
Joseph Lizier 9f9c79bc95 Handling infinites in Chi square CDF function properly 2019-05-17 22:24:54 +10:00
Joseph Lizier 8542d217ea Added support for Chi^2 analytic distribution to support degrees of freedom 0 (this will handle e.g. where a source had no independent dimensions) 2019-05-17 22:20:54 +10:00
Joseph Lizier fce1b34a5c Adding NORMALISE and NOISE_LEVEL_TO_ADD properties to all conditional mutual information calculators for continuous-valued data (extends this capability from only KSG to Gaussian as well) 2019-04-03 00:12:00 +11:00
Joseph Lizier d9db7a15ab Further clarifications for including NORMALISE and NOISE_LEVEL_TO_ADD properties to all mutual information calculators, and handling linear redundancy sub-cases 2019-04-03 00:07:05 +11:00
Joseph Lizier b1437452e4 Adding NORMALISE and NOISE_LEVEL_TO_ADD properties to all mutual information calculators for continuous-valued data (extends this capability from only KSG to Gaussian and kernel as well, the latter already had NORMALISE) 2019-04-02 12:38:17 +11:00
Joseph Lizier ecec4d20e3 Added unit tests for linear dependency possibilities for issue #16 2019-03-31 23:22:55 +11:00
Joseph Lizier 988d32de70 Added bug fix within recent changes to MatrixUtils Cholesky decomposition calculation, along with unit testing of the linear dependency combinations for issue #17 2019-03-31 23:21:39 +11:00
Joseph Lizier 2a0024ad83 Fixes issue #17: Handling sub-cases for linear redundancy within and across variables in the linear-Gaussian mutual information estimator. This is done by detecting such redundancies and either returning 0 or infinity as the requisite result. Mirrors how this is done for conditional MI. 2019-03-29 00:01:36 +11:00
Joseph Lizier 66676a2692 A rewrite of parts of the linear Gaussian conditional MI estimator, in order to more deftly handle linear dependencies within variables 1 and 2, and between each of them and the conditional. Previously we removed sub-variables of those arbitrarily, now the removal is targetted to those sub-variables that are problematic. Also required some variable name changes to reflect different ordering of how variables and the conditionals are concatenated in arrays. 2019-03-28 23:58:53 +11:00
Joseph Lizier d58c393c53 Added methods to MatrixUtils to make a Cholesky decomposition of independent components only (useful for MI and conditional MI calculations), with a required update to the NonPositiveDefiniteMatrixException to include a field defining which row in the matrix was a problem. Also includes code to convert between native int[] arrays and ArrayList<Integers>, and new method signatures for column selection from matricies.
Also added new unit tests for the Cholesky decomposition.
2019-03-28 23:52:47 +11:00
Joseph Lizier 1d2c7c42b9 Updating javaMatrixToOctave to handle new conversion routine in octave (and be backwards compatible to old) 2019-03-21 09:35:41 +11:00
Joseph Lizier 9aed0d4590 Merge remote branch 'origin/master' 2019-03-11 12:04:18 +11:00
Joseph Lizier c4349140f1 Updating ant javadoc target to use packageset instead of fileset (for JDK >= 8 it seems that fileset is not properly handling the java source code I want the javadocs to ignore; packageset is doing this ok). Fixes Issue #75 (the javadocs part) 2019-03-11 11:58:17 +11:00
David Shorten 4985def021 fixed weirdness 2019-02-01 15:35:26 +11:00
Joseph Lizier c693b5d57e
Edited funding acknowledgements on README.md 2019-02-01 13:38:35 +11:00
David Shorten ea8a322b61 end Tues 2019-01-29 19:51:21 +11:00
David Shorten fcbf5e7dac end Thurs 2019-01-22 19:17:36 +11:00
David Shorten 8bcf41e572 end Wed 2018-12-19 17:15:47 +11:00
David Shorten 504c6262f0 end Tues 2018-12-18 20:32:37 +11:00
David Shorten 23abc021ac modification to calculation for point inclusion 2018-12-11 16:15:03 +11:00
David Shorten 064953c584 bit of cleaning up 2018-12-11 15:18:51 +11:00
David Shorten b467ea22a1 option of using same K for dest history 2018-12-11 15:15:26 +11:00
David Shorten 9f51dc284c option of not doing radius trimming 2018-12-11 12:21:27 +11:00
David Shorten 6f8ae62fee option of excluding the point itself 2018-12-11 12:03:44 +11:00
David Shorten 267796dc83 forced inclusion of TransferEntropyCalculatorSpikingIntegration.java 2018-12-10 20:29:54 +11:00
David Shorten ec01683592 Incorporated JL code from 21/11/2018 2018-12-10 20:22:15 +11:00
David Shorten fa9a45a9cf added in the original spiking estimator code 2018-12-10 17:12:15 +11:00
Joseph Lizier 2ba27f30ac
Merge pull request #73 from pmediano/master
Minor updates to GPU tests and examples following v1.5 release.
2018-11-26 10:28:15 +11:00
Pedro Martinez Mediano 4908276333 GPU tests and example now compute multiple surrogates. 2018-11-25 19:45:48 +02:00
Pedro Martinez Mediano c616ba55d4 Added link to wiki in GPU loader error message. 2018-11-25 19:25:33 +02:00
jlizier bd6a9a2601 Updating links to latest release to v1.5 on front page. Also fixed indenting 2018-11-26 00:33:58 +11:00
jlizier eefe1e1a8b Updating readme-template.txt and ready for release v1.5 2018-11-25 23:48:10 +11:00
jlizier ee1ef4909c Storing executable permissions for jar file, .sh and .bat files in the distribution .zip and now making a .tar.gz distribution also 2018-11-25 23:39:44 +11:00
jlizier a3ec963618 Updating demos PDFs again 2018-11-25 23:38:49 +11:00
jlizier 603445651c Moving GPU readme from wiki into CUDA folder 2018-11-25 23:27:27 +11:00
jlizier 7bd6496a40 Removed old .sh and .bat files for running AutoAnalyser for individual measures (now replaced by launchAutoAnalyser) 2018-11-25 22:38:08 +11:00
jlizier cd1d4c2684 Adding executable permission to Java demo 10 for GPU 2018-11-25 21:57:25 +11:00
jlizier 7910828ad7 Added release notes for v1.5 to readme-template.txt 2018-11-25 21:52:07 +11:00
jlizier dc4e59f945 Updating tutorial wiki page PDF 2018-11-25 21:50:53 +11:00
jlizier b6a5285b9b Updated version number in build.xml ready for new release 2018-11-25 21:48:29 +11:00
jlizier 3c24debea5 Updating PDFs of wiki pages of all demos to make sure they are up to date; includes adding the new wiki page for GPU 2018-11-25 21:47:41 +11:00
jlizier 16015e0f12 Nearest neighbour searchers now return number of points found for findPointsWithinR as well as marking them in input arrays. Also added new method sumDistanceAboveThresholdForPointsWithinRs() for the univariate searcher (to be used in spiking TE estimator under development) 2018-11-24 21:16:36 +11:00
David Shorten af7fbd6c37 added spiking measures 2018-11-19 15:55:24 +11:00
jlizier 8909c23fcc Incorporated auto-embedding in the TE multivariate via conditional MI common class. Much of the code is moved up from the TE multivariate KSG estimator; now the functionality is provided for multivariate Gaussian as well. Also necessitated adding the max_cor_num_surrogates property to TE multivariate Gaussian, and took the opportunity to make much of the whitespace here consistent, and unit tests added for Gaussian (tweaked slightly for KSG) 2018-10-18 00:58:17 +11:00
jlizier 42f8d01e26 Adding property of number of dimensions for the AIS multivariate calculator (and implemented in the via MI common class). Needed this to make multivariate TE embedding a bit neater, and it should be there anyway. 2018-10-18 00:51:37 +11:00
jlizier e1bad39e4e Added proper full definitions for the methods of the AIS multivariate interface; much of this is achieved by extending the univariate AIS interface (which mandates that the univariate methods must be supported). No current child classes required any changes as they all supported these already. Removed superfluous documentation in the AIS multivariate via MI class (as well as fixing whitespace inconsistencies therein) 2018-10-17 23:37:43 +11:00
jlizier da418c31a0 Added new auto-embedding capability for TE Gaussian into the AutoAnalyser GUI demo. Also added new auto-embedding drop down option of Max corrected AIS + TE for KSG as well, and debugged the getProperty returning of the number of nearest neighbours for Ragwitz criteria now that this occurs in the common superclass instead of in KSG (and gave this a reasonable default of 4) 2018-10-17 14:23:20 +11:00
jlizier a34bce25ba Enabled auto-embedding for TE Gaussian. Did so by bringing up auto-embedding for TE functionality up from the KSG estimator to the via Conditional MI class. Also added new property to Gaussian TE for number of surrogates to use for bias correction in embedding (if not using analytic bias correction), like Gaussian AIS. This also necessitated adding an empty preFinaliseAddObservations() method to the TE Gaussian multivariate estimator, to ensure it did not yet try to autoembed until that is enabled in the multivariate calculator. Unit tests included here as well (included using more samples for TE KSG autoembedding to ensure we get the correct answer more reliably -- should probably add a stronger effect for that too). 2018-10-17 13:49:09 +11:00
jlizier efb8243ed7 Altering TE Kraskov to do auto-embedding properly when we have added multiple observations with validity vectors. Also taking the opportunity to re-engineer the internals to lay groundwork for auto-embedding function to be shared with the Gaussian estimator at a later stage. Unit tests added here as well for the above. 2018-10-15 20:56:50 +11:00
jlizier 2ff6d8aeec Added getProperty for AIS Kraskov multivariate. Need to re-engineer this class for proper code re-use anyway. 2018-10-15 14:38:46 +11:00
jlizier 3aa1493d7f Added addObservations() method with sourceValid and destValid boolean arrays to TransferEntropyCalculatorViacondMutualInfo class 2018-09-21 10:34:01 +10:00
jlizier 6cf43db7f5 Updating lecture slides for the course all to 2018 versions 2018-09-20 14:15:11 +10:00
jlizier cf83a73bc0 Renaming lecture slide files in the course to align with new numbering and naming 2018-09-20 14:11:14 +10:00
jlizier 1f8a33b211 Changing folder structure for the course modules 2018-09-20 14:04:10 +10:00
jlizier 19be59c118 Added Acknowledgements section to README.md 2018-09-17 20:51:17 +10:00
jlizier af1173ba5b Patching local MI discrete computation when we have a time difference of > 0 (we were getting an ArrayIndexOutOfBoundsException before) 2018-09-05 13:43:21 +10:00
jlizier 9dbe2f8578 Added to AutoAnalyser GUI for AIS surrogate-based bias correction (parameter being the number of surrogates) for max AIS corrected auto embedding, for kernel estimator as well as Gaussian (as an alternative to analytic). Also includes the implementing code for AIS Gaussian (was already committed for kernel) 2018-08-27 14:24:05 +10:00
jlizier 1c2082e74a Adding a new data set with 2 step Gaussian self dependence plus noise 2018-08-27 14:09:16 +10:00
jlizier ad31af03a7 Added throws Exception for computeSignificance() on multivariate Gaussian AIS calculator, because of throws clause introduced on underlying MI estimator 2018-08-27 13:21:29 +10:00
jlizier f502497256 Added bias correction option to AutoAnalyser GUI for Gaussian AIS, TE and CTE estimators 2018-08-27 13:19:00 +10:00
jlizier 7f9b1c0812 Patching bias correction for Guassian MI and CMI (some for MI was in line with previous work for CMI, which required extending here). Unit tests included. 2018-08-27 13:17:58 +10:00
jlizier fdec72aeff Added tracking of bias correction to ChiSquaredMeasurementDistribution, so the distribution is adjusted with bias correction. Should have been sent with previous commit for patch to CMI Gaussian bias correction 2018-08-27 00:29:59 +10:00
jlizier c32b8de8b0 Fixed a hanging issue with analytic bias correction for Guassian CMI, and added to AutoAnalyser GUI 2018-08-27 00:22:02 +10:00
jlizier b1a02be7db Adding sanity check that discrete ContextOfPastMeasure (and child classes, including AIS and TE) have k >= 0. 2018-08-26 22:48:37 +10:00
jlizier dc08e1c372 Catching OutOfMemoryError in Discrete calculator creation for all other discrete calculators (only MI was done in the previous commit). Also simplified constructor calls (with code re-use) for conditional TE. 2018-08-25 22:27:29 +10:00
jlizier 93c767999e Catching OutOfMemoryError in Discrete MI calculator creation 2018-08-25 20:59:05 +10:00
jlizier 908cf675a8 Added new constructor for TE Kraskov to pass in KSG algorithm number as an integer (It's not likely that it will be needed, but is there for completeness to match the AIS one) 2018-08-24 14:48:11 +10:00
jlizier 373ebbdd56 Enabling AIS KSG calculator to have underlying KSG algorithm changed via the "ALG_NUM" property 2018-08-24 14:47:21 +10:00
jlizier 7f4dfa7970 Added bias correction property for Gaussian MI to AutoAnalyser GUI 2018-08-22 16:00:52 +10:00
jlizier 323ef47475 Adding auto-embedding properies to AutoAnalyser GUI Active Info Storage for all continuous calculators (was only in KSG before) 2018-08-22 15:53:09 +10:00
jlizier 4b6fc39c72 Fixed tool tip pop-ups for Discrete and Binned estimators in AutoAnalyser GUI (they were using spurious values from a continuous calculator before) 2018-08-21 20:56:58 +10:00
jlizier d69d503492 Allowing figure number to be specified in plotOptions for Matlab/Octave plotLocalInfoMeasureFoooorCA 2018-08-21 20:54:41 +10:00
jlizier a4b9f20801 Java matrix to matlab conversion was accidentally falling through to element by element; was correct but slow. Fixed this, should be more efficient now 2018-08-20 10:30:28 +10:00
jlizier 97e46c66a3 Added extract of SFI heart rate - breath rate file, for simpler analysis of only a clean part of the data. 2018-08-10 15:52:15 +10:00
jlizier 093737951f Updating checking of expected jar location in all python demo scripts, mirroring what was done on previous commit for example1 script 2018-06-28 00:04:08 +10:00
jlizier a278060056 Adding error check on python demo 1 that script is called from correct demos/python directory 2018-06-27 20:49:32 +10:00
jlizier 8c5aa51f57 AutoAnalyser: Added drop-down menus (aka comboboxes) for parameters whose values are amenable to selection in this way. All child classes updated to be compatible. GUI size adjusted here also. 2018-06-26 12:22:05 +10:00
jlizier 7fafabe451 Extending MI discrete calculator to allow different bases for each variable. This necessitates immediate removal of the (int,int) constructor (where the 2nd argument was the time difference), this will now be confusing between (base, timeDiff) and (base1, base2). In time we may bring it back, after we can be reasonably comfortable people have switched away from using (base, timeDiff). 2018-06-20 10:55:21 +10:00
jlizier 4170339426 Moving check of dimensionality for continuous variables in mixed CMI calculator common to the main setObservations() method 2018-06-19 23:57:41 +10:00
jlizier ca909dc60f Adding check of dimensionality of observations supplied to multivariate AIS calculators when univariate is expected. 2018-06-19 23:45:00 +10:00
jlizier 5bde6f295b Fixes issue #70 by providing setObservations(double[], int[], double[]) methods for the mixed CMI calculators (i.e. allowing univariate arrays to be passed in if dimension 1 was defined for both the continuous data and conditional). Unit test validating is included. 2018-06-19 23:08:13 +10:00
jlizier fd13b75be3 Making CA local info values plotting utility make uniform plots of zero be all white (contributed by Conor Finn) 2018-06-08 21:25:32 +10:00
jlizier de5661b1e3 Added encoding="UTF8" to the javac call, after getting a report of a user with javac problems (seemingly with platform default encoding not matching UTF8) 2018-05-31 10:33:31 +10:00
jlizier 643212840a Making indenting style consistent through file 2018-05-18 08:56:47 +10:00
jlizier fa9db58945 In AIS Gaussian unit test, switching property names for auto embedding to now reference the super class (AIS via Mutual Info) 2018-05-16 22:44:32 +10:00
jlizier 4ff4e4bfc9 Added unit tests for AIS Multivariate Gaussian calculator, including on auto-embedding, and that it functions ok for univariate data. 2018-05-16 22:43:46 +10:00
jlizier dfe7ef0334 Altering AIS Multivariate Via Mutual Info calculator -- and child classes, now including kernel estimator -- to support auto-embedding primarily via the parent methods of the univariate AIS calculator.
Also includes patching functionality when dimension == 1 to always use the underlying AIS univariate calculator consistently, and adding missing methods on adding observations with validity array.
Also includes some minor alterations to error messages.
Gaussian and Kernel Multivariate AIS calculators have the computeAdditionalBiasToRemove()  method implemented now to allow this; Gaussian calculator also adds the analytic computeSignificance() method, whilst Kernel calculator also adds a property for the number of surrogates to use in bias correction.
2018-05-16 22:42:32 +10:00
jlizier fcd30c6716 Minor changes to Javadocs for AIS kernel 2018-05-16 22:28:19 +10:00
jlizier a649b38270 Patched new section of AIS calculator via MI, whereby addObservationsWithGivenParams() when called with a validity[] array did not compute valid start and end time pairs for the candidate k and tau, but did so for the k and tau set in the properties. Fixed so that the candidate k and tau can be supplied. 2018-05-16 14:39:54 +10:00
jlizier e8603b08f8 Moving auto-embedding for AIS (Ragwitz and maximum bias-corrected AIS methods) from out of Gaussian and KSG calculators and into the common AIS calculator via MI class. The common implementation then allows us to introduce auto-embedding for the AIS kernel estimator as well (included requiring adding a property for the number of surrogates to use to compute the bias for this one).
These changes now incorporate auto-embedding for all AIS continuous calculators, partially addressing issue #38
2018-05-16 14:20:08 +10:00
jlizier 1c591925bd Added auto-embedding to Gaussian AIS calculator, with both Ragwitz and maximum bias-corrected AIS methods. Bias-correction implemented via the Gaussian analytic surrogates. Involves defining new properties, setProperty, getProperty and preFinaliseAddObservations() to do the embedding. Unit test included also, mirroring unit testing for KSG AIS (which used linear Gaussian variables). 2018-05-15 17:35:06 +10:00
jlizier 48b48ab845 Changing AIS Via Mutual Info internal addObservationsAfterParamsDetermined method to addObservationsWithGivenParams - taking k and tau as arguments rather than using the internal ones. This allows the method to be called by auto-embedding in the child classes as well (better code re-use ready for extending auto-embedding) 2018-05-15 17:32:50 +10:00
jlizier 9552091fca Adding Javadoc on header for neighbour counts method in KSG MI estimator 1 2018-05-15 17:28:39 +10:00
jlizier 0b70e92efc Added Bias-correction property to Gaussian MI and conditional MI calculators, including set and getProperty and an implementation in the calculations. This implements bias-correction by substracting the bias (of the analytic chi^2 based null distribution) from the calculations. 2018-05-13 22:29:17 +10:00
jlizier c0b9d736d7 Added methods to retrieve mean and standard deviation of the Chi^2 null distribution, as well as (empirical) unit test for this. 2018-05-13 22:02:46 +10:00
jlizier 46a9785da2 In surrogates for MI and CMI also turning adding noise off since this will have been done in the initial calculation already, and will just broaden the noise here. 2018-05-12 22:35:54 +10:00
jlizier 28ba409ff6 Turning off normalisation when computing surrogates in Common CMI and MI calculators, because normalisation has already been carried out (and if one variable had no variance, this will inflate the values back to original scale) 2018-05-12 21:30:39 +10:00
jlizier 0e4455b2fd Corrects the access at one point to the bins for the data points in the multivariate kernel estimator, which should use an IntArray object but did use an int[] object to access . Fixes #69. 2018-05-10 20:20:02 +10:00
jlizier 860d43dbca Adding additional error message for Exception during KSG Active Info Storage auto-embedding 2018-05-07 23:15:33 +10:00
jlizier 1f625b59f0 AutoAnalyser: fixing bug where column numbers for data are all set to zero if the user unclicks the "compute result?" button 2018-05-07 22:57:10 +10:00
jlizier d1bba0e4c1 Adding computeLocalOfPreviousObservations() to continuous Entropy estimator interface and all underlying implementations. Added unit tests that locals should average back ok. Also fixing multivariate Entropy estimator interface to implement the univariate interface also (and fixing underlying implementations to comply) 2018-04-27 11:20:25 +10:00
jlizier bf0062b902 Switching new debug method in KSG conditional MI calculator 1 to be publicly accessible 2018-04-26 11:43:04 +10:00
jlizier 7d76f82bb2 Adding partialNeighbourCountFromObservations() method to KSG conditional MI calculator 1 for debugging investigations into the neighbour counts 2018-04-26 11:24:56 +10:00
Joseph Lizier 5b569c63dc
Merge pull request #68 from pmediano/master
Added new autoembedding methods to multivariate KSG TE calculator, including new option of optimising source embedding for maximum TE (after target embedding for maximum AIS is done) on both the multivariate and univariate KSG TE calculator.
2018-04-23 16:22:33 +10:00
Pedro Martinez Mediano c15c643a09 Added tests for new embeddings in univariate KSG TE calculator. 2018-04-22 22:25:40 +01:00
Pedro Martinez Mediano df8eec27cd Added MAX_CORR_AIS_AND_TE embedding to univariate KSG TE calculator. 2018-04-22 22:25:05 +01:00
Pedro Martinez Mediano f8bca3275d Fixed docs for new MAX_CORR_AIS_AND_TE embedding method. 2018-04-22 20:45:06 +01:00
Joseph Lizier 9c40d7fadc
Fixed wiki link on homepage
Fixed wiki link for ImplementedMeasures on the homepage
2018-03-16 10:47:45 +11:00
Pedro Martinez Mediano 02dad26a94 Added brief mention of AUTO_EMBED_METHOD_MAX_CORR_AIS_AND_TE to javadocs. 2018-02-27 20:29:39 +00:00
Pedro Martinez Mediano 03d5e2fb2f Added tests for new TE autoembedding methods. 2018-02-27 20:18:28 +00:00
Pedro Martinez Mediano 5f6671aa2b Added AUTO_EMBED_METHOD_MAX_CORR_AIS_AND_TE to multivariate KSG TE. 2018-02-27 20:18:04 +00:00
Pedro Martinez Mediano d4c9b28973 Fixed error in KSG TE multivariate tester.
Tester was wrongly calling the univariate version of the algorithm using
the first column of the input.
2018-02-27 20:16:44 +00:00
Pedro Martinez Mediano 550ff793eb Fixed bug in KSG TE multivariate embeddings and setObservations. 2018-02-27 20:14:08 +00:00
Pedro Martinez Mediano 438a88c97c Added unittests for multivariate KSG TE autoembedding. 2018-02-27 17:56:42 +00:00
Pedro Martinez Mediano 8be6a037af Added auto-embedding methods to multivariate KSG TE calculator. 2018-02-25 19:23:09 +00:00
Pedro Martinez Mediano ce4b1599c6 Added MAX_CORR_AIS embedding method to multivariate KSG AIS. 2018-02-25 18:57:15 +00:00
Pedro Martinez Mediano 75bb2c814a Added addObservations-related methods to multivariate TE calculators.
This is needed to implement auto-embedding methods later.
2018-02-25 18:54:36 +00:00
Joseph Lizier fa0bc96a6f
Merge pull request #67 from pmediano/master
Add new set- and addObservations overloadings in KSG mixed calculator
2018-01-29 12:13:51 +11:00
Pedro Martinez Mediano 08f25beee6 Add tests for new overloadings in KSG mixed calc. 2018-01-12 22:23:12 +00:00
Pedro Martinez Mediano b0fc309d6a Add overloadings for 1d continuous variables in KSG mixed calc. 2018-01-12 22:22:46 +00:00
jlizier b32d9443eb Including the new "course" folder in the distribution produced by ant 2018-01-09 11:41:41 +11:00
jlizier 9feff283c4 First versions of Lecture slides for information theory course uploaded. Tutorial activities and sample code to come later. 2018-01-09 11:39:46 +11:00
jlizier 0278f95ae9 Enabled use of USE_GPU property for KSG calculators in the AutoAnalysers for CMI, TE, CTE and AIS 2017-12-30 12:03:17 +11:00
Joseph Lizier 6b5e3237ed
Merge pull request #65 from pmediano/master
Added GPU implementation of KSG CMI calculator
2017-12-21 12:01:10 +11:00
Pedro Martinez Mediano 92f1154e3d Added smoke junit tests for GPU CMI reordering. 2017-12-19 20:43:25 +00:00
Pedro Martinez Mediano 64f1142b40 Added argument to choose which variable to reorder in GPU CMI code. 2017-12-19 20:42:58 +00:00
Pedro Martinez Mediano 65ac0e9ff8 Removed unnecesary overloaded method in KSG CMI calc. 2017-12-19 20:41:11 +00:00
Pedro Martinez Mediano 2c518ab436 Merge branch 'master' into gpu 2017-12-18 18:53:57 +00:00
Pedro Martinez Mediano 76e7277e95 Removed unnecessary prints in GPU C unit tests. 2017-12-18 18:43:01 +00:00
Pedro Martinez Mediano 82593e1db2 Refactored gpuKnn functions for digamma calculation. 2017-12-18 18:27:05 +00:00
Pedro Martinez Mediano 4949a1079d Added junit KSG GPU CMI tests. 2017-12-18 17:51:03 +00:00
Pedro Martinez Mediano 2f1cd192b8 Fixed small typo in Java KSG CMI calculator. 2017-12-18 17:50:37 +00:00
Pedro Martinez Mediano 39fb538945 Added C CMI unit tests. 2017-12-18 17:49:50 +00:00
Pedro Martinez Mediano fc40c279cd Added final code to call gpuCMI functions from JNI. 2017-12-18 17:49:32 +00:00
Pedro Martinez Mediano 75a303875d Replaced stub functions in gpuCMILibrary with correct code. 2017-12-18 17:48:57 +00:00
Pedro Martinez Mediano f1bd757dc0 Added versions of gpuKnn functions adapted for CMI. Refactoring needed. 2017-12-18 17:47:53 +00:00
Pedro Martinez Mediano 1fb4015df5 Remove debug mode from junit GPU MI tests. 2017-12-18 17:43:15 +00:00
Joseph Lizier a9dac705a8
Merge pull request #64 from pmediano/master
Improvements to Kozachenko multivariate entropy calculator.

Looks great, thanks Pedro. Fixes issue #56, will close it
2017-12-18 15:56:22 +11:00
Pedro Martinez Mediano d0304ae0c4 Added Java-side JNI functions and ensureKdTreesConstructed to KSG CMI. 2017-12-12 11:19:40 +00:00
Pedro Martinez Mediano 9248005de5 Added stub JNI function for KSG CMI. 2017-12-12 11:18:27 +00:00
Pedro Martinez Mediano 6a13b80531 Added stub gpuCMILibrary and updated Makefile. 2017-12-12 11:17:48 +00:00
Pedro Martinez Mediano b7dd2fca5f Moved common defs from gpuMILibrary to gpuKnnLibrary.
In preparation for gpuCMILibrary.
2017-12-12 11:16:03 +00:00
Pedro Martinez Mediano f4ca442de4 Now KSG MI calc does not build KdTrees if GPU is going to be used. 2017-12-12 11:10:50 +00:00
Pedro Martinez Mediano d010f32635 Updated getProperty and removed spurious dependency in KSG MI calc. 2017-12-12 11:04:32 +00:00
Pedro Martinez Mediano eabd7f3701 Fixed typo in Kozachenko entropy calculator. 2017-11-28 16:58:13 +00:00
Pedro Martinez Mediano 444fb70801 Added addObservations-type functions to Kozachenko entropy calculator. 2017-11-28 16:56:51 +00:00
Pedro Martinez Mediano e290040d8d Added docs to Kozachenko entropy calculator. 2017-11-28 16:26:46 +00:00
Pedro Martinez Mediano 35df6ca3da Kozachenko entropy estimator now adds noise to data by default. 2017-11-28 16:04:09 +00:00
jlizier 9c96ceb850 Fixed logic for when parameter values (in particular auto-embedded properties) are written back into the properties table after the calculation. This was happening only when we had the "all pairs" option selection, when it should only happen when this is not selected. 2017-11-28 12:36:06 +11:00
228 changed files with 33551 additions and 2922 deletions

View File

@ -1,6 +1,6 @@
# Java Information Dynamics Toolkit (JIDT)
Copyright (C) 2012-2014 [Joseph T. Lizier](http://lizier.me/joseph/); 2014-2016 [Joseph T. Lizier](http://lizier.me/joseph/) and Ipek Özdemir; 2017- [Joseph T. Lizier](http://lizier.me/joseph/), Ipek Özdemir and [Pedro Mediano](https://www.doc.ic.ac.uk/~pam213/)
Copyright (C) 2012- [Joseph T. Lizier](http://lizier.me/joseph/); 2014- Ipek Özdemir; 2017- [Pedro Mediano](https://www.doc.ic.ac.uk/~pam213/); 2019- Emanuele Crosato, Sooraj Sekhar, Oscar Huaigu Xu; 2022- [David Shorten](https://scholar.google.com/citations?user=ggF3Lt4AAAAJ&hl=en)
*JIDT* provides a stand-alone, open-source code Java implementation (also usable in [Matlab, Octave](../../wiki/UseInOctaveMatlab), [Python](../../wiki/UseInPython), [R](../../wiki/UseInR), [Julia](../../wiki/UseInJulia) and [Clojure](../../wiki/UseInClojure)) of information-theoretic measures of distributed computation in complex systems: i.e. information storage, transfer and modification.
@ -8,19 +8,25 @@ JIDT includes implementations:
* principally for the measures **transfer entropy**, **mutual information**, and their conditional variants, as well as **active information storage**, entropy, etc;
* for both _discrete_ and _continuous_-valued data;
* using various types of estimators (e.g. _Kraskov-Stögbauer-Grassberger estimators_, _box-kernel estimation_, _linear-Gaussian_),
as described in full at ImplementedMeasures.
as described in full at [ImplementedMeasures](../../wiki/ImplementedMeasures).
JIDT is easy to use:
* It ships with a **GUI application** -- the [AutoAnalyser](../../wiki/AutoAnalyser), see picture below -- to facilitate point-and-click analysis, as well as code template generation for more complex analysis.
* We provide **short video lectures** and corresponding slides in a (beta) [Course](../../wiki/Course) on how to understand using information-theoretic tools to analyse complex systems, and to implement such analysis with JIDT.
JIDT is distributed under the [GNU GPL v3 license](http://www.gnu.org/licenses/gpl.html) (or later).
# Getting started
1. [Download](../../wiki/Downloads) and [Installation](../../wiki/Installation) is very easy!
1. _Quick start_: download the latest [v1.4 full distribution](http://lizier.me/joseph/software/jidt/download.php?file=infodynamics-dist-1.4.zip) (suitable for all platforms) and see the readme.txt file therein.
1. [Documentation](../../wiki/Documentation) including: the paper describing JIDT at [arXiv:1408.3270](http://arxiv.org/abs/1408.3270) (distributed with the toolkit), a [Tutorial](../../wiki/Tutorial), and [Javadocs (v1.4 here)](http://lizier.me/joseph/software/jidt/javadocs/v1.4/);
1. [Demos](../../wiki/Demos) are included with the full distribution, including a [GUI app](../../wiki/AutoAnalyser) for automatic analysis and code generation (see picture below), [simple java demos](../../wiki/SimpleJavaExamples) and [cellular automata (CA) demos](../../wiki/CellularAutomataDemos).
1. These Java tools can easily be used in [Matlab/Octave](../../wiki/OctaveMatlabExamples), [Python](../../wiki/PythonExamples), [R](../../wiki/R_Examples), [Julia](../../wiki/JuliaExamples) and [Clojure](../../wiki/Clojure_Examples)! (click on each language here for examples)
1. [Download](../../wiki/Downloads) and [Installation](../../wiki/Installation) is very easy!
1. _Quick start_: take a `git clone` (then build via [AntScripts](../../wiki/AntScripts)) OR download the latest [v1.6.1 full distribution](https://lizier.me/joseph/software/jidt/download.php?file=infodynamics-dist-1.6.1.zip) (suitable for all platforms) and see the readme.txt file therein.
1. [Documentation](../../wiki/Documentation) including: the paper describing JIDT at [arXiv:1408.3270](http://arxiv.org/abs/1408.3270) (distributed with the toolkit), a (beta) [Course](../../wiki/Course) including short video lectures and a shorter [Tutorial](../../wiki/Tutorial), and [Javadocs (v1.6.1 here)](https://lizier.me/joseph/software/jidt/javadocs/v1.6.1/);
1. [Demos](../../wiki/Demos) are included with the full distribution, including a [GUI app](../../wiki/AutoAnalyser) for automatic analysis and code generation (see picture below), [simple java demos](../../wiki/SimpleJavaExamples) and [cellular automata (CA) demos](../../wiki/CellularAutomataDemos).
1. These Java tools can easily be used in [Matlab/Octave](../../wiki/OctaveMatlabExamples), [Python](../../wiki/PythonExamples), [R](../../wiki/R_Examples), [Julia](../../wiki/JuliaExamples) and [Clojure](../../wiki/Clojure_Examples)! (click on each language here for examples)
![Computing in the GUI app image](https://raw.githubusercontent.com/jlizier/jidt/master/web/AutoAnalyserGUI-2-Compute.png)
[![Computing in the GUI app image](https://raw.githubusercontent.com/jlizier/jidt/master/web/AutoAnalyserGUI-2-Compute.png)](../../wiki/AutoAnalyser)
[![Course and video lectures](https://raw.githubusercontent.com/jlizier/jidt/master/web/YouTubePlaylist.png)](../../wiki/Course)
For further information or announcements:
* Join our discussion group: http://groups.google.com/d/forum/jidt-discuss
@ -39,6 +45,28 @@ See other [PublicationsUsingThisToolkit](../../wiki/PublicationsUsingThisToolkit
# News
_22/08/2023_ - New full distribution files available for **release v1.6.1**; Changes for v1.6.1 include:
Minor updates to supporting use in Python, including virtual environments;
Minor tweaks to fish schooling examples (mostly comments).
_5/09/2022_ - New full distribution files available for **release v1.6**; Changes for v1.6 include:
Adding Flocking/Schooling/Swarming demo;
Included Pedro's code on IIT and O-/S-Information measures;
Spiking TE estimator added from David;
Fixed up AutoAnalyser to work well for Python3 and numpy;
Links to lecture videos included in the beta wiki for the course;
Added rudimentary effective network inference (simplified version of the IDTxl full algorithm) in demos/octave/EffectiveNetworkInference;
_26/11/2018_ - New jar and full distribution files available for **release v1.5**; Changes for v1.5 include:
Added GPU (cuda) capability for KSG Conditional Mutual Information calculator (proper documentation to come), brief [wiki page](../../wiki/GPU) and unit tests included;
Added auto-embedding for TE/AIS with multivariate KSG, and univariate and multivariate Gaussian estimator (plus unit tests), for Ragwitz criteria and Maximum bias-corrected AIS, and also added Maximum bias corrected AIS and TE to handle source embedding as well;
Kozachenko entropy estimator adds noise to data by default;
Added bias-correction property to Gaussian and Kernel estimators for MI and conditional MI, including with surrogates (only option for kernel);
Enabled use of different bases for different variables in MI discrete estimator;
All new above features enabled in AutoAnalyser;
Added drop-down menus for parameters in AutoAnalyser;
Included long-form lecture slides in course folder;
_26/11/2017_ - New jar and full distribution files available for **release v1.4**; Changes for v1.4 include:
Major expansion of functionality for AutoAnalysers: adding Launcher applet and capability to double click jar to launch, added Entropy, CMI, CTE and AIS AutoAnalysers, also added binned estimator type, added all variables/pairs analysis, added statistical significance analysis, and ensured functionality of generated Python code with Python3;
Added GPU (cuda) capability for KSG Mutual Information calculator (proper documentation and wiki page to come), including unit tests;
@ -122,3 +150,11 @@ _19/11/2012_ - New jar and full distribution files available for v0.1.2, includi
_31/10/2012_ - Jar and full distribution files available for v0.1.1 (first distribution)
_7/5/2012_ - JIDT project created and code uploaded
# Acknowledgements
This project has been supported by funding through:
* Australian Research Council Discovery Early Career Researcher Award (DECRA) "Relating function of complex networks to structure using information theory", J.T. Lizier, 2016-19 DE160100630
* Universities Australia - Deutscher Akademischer Austauschdienst (German Academic Exchange Service) UA-DAAD Australia-Germany Joint Research Co-operation grant "Measuring neural information synthesis and its impairment", Wibral, Lizier, Priesemann, Wollstadt, Finn, 2016-17
* University of Sydney Research Accelerator (SOAR) Fellowship 2019 Scheme, J.T. Lizier (CI), 2019-2020
* Australian Research Council Discovery Project "Large-scale computational modelling of epidemics in Australia: analysis, prediction and mitigation", M. Prokopenko, P. Pattison, M. Gambhir, J.T. Lizier, M. Piraveenan, 2016-19 DP160102742

View File

@ -5,12 +5,13 @@
</description>
<!-- set global properties for this build -->
<property name="version" value="1.4"/>
<property name="version" value="1.6.1"/>
<property name="mainfilename" value="infodynamics"/>
<property name="jarplainname" value="${mainfilename}.jar" />
<property name="jarversiondistnamezip" value="${mainfilename}-jar-${version}.zip" />
<property name="distname" value="${mainfilename}-dist-${version}" />
<property name="distnamezip" value="${distname}.zip" />
<property name="distnametargz" value="${distname}.tar.gz" />
<property name="src" location="java/source"/>
<property name="cudasrc" location="cuda"/>
<property name="bin" location="bin"/>
@ -42,17 +43,17 @@
<!-- Compile the java toolkit -->
<target name="compile" depends="init" description="compile the source">
<!-- Compile to Java 6 to provide compatibility for users with older JREs.
<!-- Compile to Java 8 to provide compatibility for users with older JREs.
Caveat: The flags here only check the language compatibility, but
may still use newer libraries which may cause issues for users with JDK 6.
Indeed, one gets the warning: "bootstrap class path not set in conjunction with -source 1.6"
may still use newer libraries which may cause issues for users with JDK 8.
Indeed, one gets the warning: "bootstrap class path not set in conjunction with -source 1.8"
To fix this, one would use the bootstrap classpath to point our JDK to an rt.jar
for Java 6.
At this stage, I'm sure I'm not using new library calls from Java 7/8, so we can
ignore the warning, and I don't want to bother installing Java 7 just to compile
like this. I'll endeavour not to use JDK 8 libraries so as not to cause
for Java 8.
At this stage, I'm sure I'm not using new library calls from Java 9+, so we can
ignore the warning, and I don't want to bother installing newer Java just to compile
like this. I'll endeavour not to use JDK 9+ libraries so as not to cause
any issues here ... -->
<javac srcdir="${src}" destdir="${bin}" includeAntRuntime="false" target="1.6" source="1.6">
<javac srcdir="${src}" destdir="${bin}" includeAntRuntime="false" target="1.8" source="1.8" encoding="UTF8">
<classpath refid="apache-classpath"/>
</javac>
@ -115,12 +116,12 @@
<target name="javadocs" depends="compile" description="Make the javadocs for the toolkit">
<delete dir="${javadocsdir}"/>
<javadoc destdir="${javadocsdir}">
<fileset dir="${src}">
<include name="**/*.java"/>
<exclude name="infodynamics/demos/**/*.java"/>
<exclude name="**/commonsmath3/*.java"/>
<exclude name="**/commonsmath3/**/*.java"/>
</fileset>
<packageset dir="${src}">
<include name="**"/>
<exclude name="infodynamics/demos/**"/>
<exclude name="**/commonsmath3/*"/>
<exclude name="**/commonsmath3/**"/>
</packageset>
</javadoc>
<!-- Change some of the style in the javadocs css for our lists: -->
<concat destfile="${javadocsdir}/stylesheet.css" append="true">
@ -148,6 +149,7 @@
<delete file="demos/clojure/project.clj"/>
<delete file="${jarversiondistnamezip}"/>
<delete file="${distnamezip}"/>
<delete file="${distnametargz}"/>
<delete file="${jarplainname}"/>
<delete>
<fileset dir="demos/AutoAnalyser" includes="GeneratedCalculator.*"/>
@ -175,7 +177,7 @@
<!-- Compile and jar the toolkit with debug symbols -->
<target name="debug" depends="init" description="compile and jar with debug symbols">
<echo message="Compiling for debug"/>
<javac srcdir="${src}" destdir="${bin}" includeAntRuntime="false" target="1.6" source="1.6" debug="true">
<javac srcdir="${src}" destdir="${bin}" includeAntRuntime="false" target="1.7" source="1.7" debug="true">
<classpath refid="apache-classpath"/>
</javac>
@ -293,23 +295,30 @@
</zip>
</target>
<!-- Developer build - builds everything and makes the full distribution file -->
<!-- Developer build - builds everything and makes the full distribution file in zip and tar.gz -->
<target name="dist" depends="jar,junit,javadocs,readmefiles" description="developer: generate the full distribution">
<echo message="${ant.project.name}: ${ant.file}"/>
<zip destfile="${distnamezip}">
<fileset file="build.xml"/>
<fileset file="${jarplainname}"/>
<zipfileset file="${jarplainname}" filemode="755"/>
<fileset file="license-gplv3.txt"/>
<fileset file="readme.txt"/>
<fileset file="InfoDynamicsToolkit.pdf"/>
<fileset file="JIDT-logo.png" erroronmissingdir="false"/> <!-- This file is missing in full repository versions -->
<fileset file="${versionfile}"/>
<zipfileset dir="java" includes="**/*.java" prefix="java"/>
<zipfileset dir="demos" includes="**/*.*,**/*" excludes="clojure/deploy,clojure/deploy/*.*,python/*.pyc" prefix="demos"/>
<zipfileset dir="demos" includes="**/*.*,**/*" excludes="clojure/deploy,clojure/deploy/*.*,python/*.pyc,**/*.sh,**/*.bat" prefix="demos"/>
<zipfileset dir="demos" includes="**/*.sh,**/*.bat" prefix="demos" filemode="755"/> <!-- Do these separately to get executable permissions -->
<zipfileset dir="javadocs" includes="**/*.*,**/*" prefix="javadocs"/>
<zipfileset dir="notices" includes="**/*.*,**/*" prefix="notices"/>
<zipfileset dir="tutorial" prefix="tutorial"/>
<zipfileset dir="cuda" prefix="cuda" excludes="benchmark.sh"/>
<zipfileset dir="cuda" prefix="cuda" includes="benchmark.sh" filemode="755"/> <!-- Do this separately to get executable permissions -->
<zipfileset dir="course" prefix="course"/>
<zipfileset dir="tutorial" prefix="tutorial"/> <!-- Get rid of this when tutorial is subsumed in course... -->
<zipfileset dir="web" includes="JIDT-logo.png" prefix="" erroronmissingdir="false"/> <!-- This file is missing in zip dist versions -->
</zip>
<tar destfile="${distnametargz}" compression="gzip" longfile="posix"> <!-- for longfiles could also use "gnu" but apparently is slightly less widely supported -->
<zipfileset src="${distnamezip}"/>
</tar>
</target>
</project>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
course/README-Course.pdf Normal file

Binary file not shown.

3
course/README.md Normal file
View File

@ -0,0 +1,3 @@
# Course
Please see the [Course page](../../../wiki/Course) on our wiki for full information about the course, including lecture slides and videos.

View File

@ -74,7 +74,7 @@ endif
# Common includes and paths for CUDA. This assumes the CUDA toolkit is in PATH
INCLUDES := -I. -I./cub -I${JNI_INCLUDE} -I${JNI_PLATFORM_INCLUDE}
LDFLAGS += -L. -L$(BIN) -lcuda -lcudart
NVCCLDFLAGS := -L. -L$(BIN) -lcuda -lcudart
.PHONY: all clean test
@ -93,7 +93,7 @@ $(BIN)/libgpuKnnLibrary.a: $(BIN)/gpuKnnLibrary.o
## Compile host code
#-------------------
c_objects = $(addprefix $(BIN)/,digamma.o gpuMILibrary.o kraskovCuda.o)
c_objects = $(addprefix $(BIN)/,digamma.o gpuMILibrary.o gpuCMILibrary.o kraskovCuda.o)
$(BIN)/%.o: %.c
${GCC} ${INCLUDES} ${CCFLAGS} -x c -std=c99 -fPIC -c $< -o $@
@ -102,7 +102,7 @@ $(BIN)/%.o: %.c
## Final shared library linking
#------------------------------
$(BIN)/libKraskov.so: $(BIN)/libgpuKnnLibrary.a $(c_objects)
${NVCC} ${NVCCFLAGS} ${INCLUDES} -Xcompiler -fPIC -shared -o $@ $(c_objects) ${LDFLAGS} -lgpuKnnLibrary
${NVCC} ${NVCCFLAGS} ${INCLUDES} -Xcompiler -fPIC -shared -o $@ $(c_objects) ${NVCCLDFLAGS} -lgpuKnnLibrary
## Test binary targets

BIN
cuda/README-GPU.pdf Normal file

Binary file not shown.

199
cuda/gpuCMILibrary.c Normal file
View File

@ -0,0 +1,199 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "gpuCMILibrary.h"
#include "gpuKnnLibrary.h"
#include "digamma.h"
#include "ctimer.h"
jidt_error_t CMIKraskov_C(int N, float *source, int dimx, float *dest, int dimy,
float *cond, int dimz, int k, int thelier, int nb_surrogates,
int returnLocals, int useMaxNorm, int isAlgorithm1, float *result,
int variableToReorder) {
return CMIKraskovWithReorderings(N, source, dimx, dest, dimy, cond, dimz,
k, thelier, nb_surrogates, returnLocals, useMaxNorm, isAlgorithm1, result,
0, NULL, variableToReorder);
}
/**
* Calculate Mutual Information using the KSG algorithm.
*/
jidt_error_t CMIKraskovWithReorderings(int N, float *source, int dimx,
float *dest, int dimy, float *cond, int dimz, int k, int thelier,
int nb_surrogates, int returnLocals, int useMaxNorm,
int isAlgorithm1, float *result, int reorderingsGiven, int **reorderings,
int variableToReorder) {
CPerfTimer pt = startTimer("Rearranging pointset");
// Allocate more space if surrogates are requested
int nchunks = nb_surrogates + 1;
int dims = dimx + dimy + dimz;
float *pointset = (float *) malloc(N * dims * nchunks * sizeof(float));
if (nb_surrogates == 0) {
memcpy( pointset, source, N*dimx*sizeof(float));
memcpy( pointset + N*dimx, cond, N*dimz*sizeof(float));
memcpy(pointset + N*(dimx+dimz), dest, N*dimy*sizeof(float));
}
if (nb_surrogates > 0) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < dimx; j++) {
pointset[j*N*nchunks+i] = source[N*j+i];
}
for (int j = 0; j < dimz; j++) {
pointset[nchunks*N*dimx + j*N*nchunks + i] = cond[N*j+i];
}
for (int j = 0; j < dimy; j++) {
pointset[nchunks*N*(dimx+dimz) + j*N*nchunks + i] = dest[N*j+i];
}
}
// If surrogates requested, copy permutations as well
int *order;
int perm[N];
if (!reorderingsGiven) {
for (int i = 0; i < N; i++) {
perm[i] = i;
}
}
for (int s = 0; s < nb_surrogates; s++) {
if (reorderingsGiven) {
order = reorderings[s];
} else {
randperm(perm, N);
order = perm;
}
for (int i = 0; i < N; i++) {
if (variableToReorder == 1) {
for (int j = 0; j < dimx; j++) {
pointset[(s+1)*N + N*j*nchunks + i] = source[N*j + order[i]];
}
for (int j = 0; j < dimz; j++) {
pointset[nchunks*N*dimx + (s+1)*N + N*j*nchunks + i] = cond[N*j + i];
}
} else {
for (int j = 0; j < dimx; j++) {
pointset[(s+1)*N + N*j*nchunks + i] = source[N*j + i];
}
for (int j = 0; j < dimz; j++) {
pointset[nchunks*N*dimx + (s+1)*N + N*j*nchunks + i] = cond[N*j + order[i]];
}
}
for (int j = 0; j < dimy; j++) {
pointset[nchunks*N*(dimx+dimz) + (s+1)*N + N*j*nchunks + i] = dest[N*j + i];
}
}
}
}
stopTimer(pt);
jidt_error_t err = CMIKraskovByPointsetChunks(N*nchunks, source, dimx,
dest, dimy, cond, dimz, k, thelier,
nchunks, returnLocals, useMaxNorm,
isAlgorithm1, result, pointset);
FREE(pointset);
return err;
}
jidt_error_t CMIKraskovByPointsetChunks(int signalLength, float *source, int dimx,
float *dest, int dimy, float *cond, int dimz, int k, int thelier, int nchunks,
int returnLocals, int useMaxNorm, int isAlgorithm1, float *result,
float *pointset) {
int dims = dimx + dimy + dimz;
int err;
int trialLength = signalLength/((float) nchunks);
float *d_source, *d_dest, *d_cond, *d_distances, *d_radii, *d_digammas;
int *d_nx, *d_ny, *d_nz, *d_indexes;
{
CPerfTimer pt = startTimer("GPU_warmup");
gpuWarmUp();
stopTimer(pt);
}
// 1. Allocate space in GPU and transfer memory
// ======================
allocateDeviceMemoryCMI(signalLength, k, dimx, dimy, dimz, &d_source, &d_dest, &d_cond,
&d_distances, &d_indexes, &d_radii, &d_nx, &d_ny, &d_nz, &d_digammas, pointset);
// 2. Find nearest neighbours in joint space
// ======================
{
CPerfTimer pt = startTimer("kNN_full");
d_cudaFindKnn(d_indexes, d_distances, d_source, d_source, k,
thelier, nchunks, dims, signalLength, useMaxNorm);
stopTimer(pt);
}
// 4. Count points strictly within R in the XZ-, YZ- and Z-spaces
// ======================
{
CPerfTimer pt = startTimer("RS_full");
d_cudaFindRSAll(d_nx, d_source, d_source, d_radii, thelier, nchunks, dimx + dimz, signalLength, useMaxNorm);
d_cudaFindRSAll(d_ny, d_cond, d_cond, d_radii, thelier, nchunks, dimy + dimz, signalLength, useMaxNorm);
d_cudaFindRSAll(d_nz, d_cond, d_cond, d_radii, thelier, nchunks, dimz, signalLength, useMaxNorm);
stopTimer(pt);
}
// 6. Set locals, surrogates or digammas for return
// ======================
{
CPerfTimer pt = startTimer("Digammas_full");
if (returnLocals) {
float digammaK = cpuDigamma(k);
float digammas[trialLength];
d_parallelDigammasCMI(digammas, d_digammas, d_nx, d_ny, d_nz, signalLength);
for (int i = 0; i < trialLength; i++) {
result[i] = digammaK - digammas[i];
}
} else {
float digammaK = cpuDigamma(k);
float sumDigammas[nchunks];
d_cudaSumDigammasCMI(sumDigammas, d_nx, d_ny, d_nz, d_digammas, trialLength, nchunks);
if (nchunks > 1) {
for (int ii = 0; ii < nchunks; ii++) {
result[ii] = digammaK - sumDigammas[ii]/((float) trialLength);
}
} else {
// Sign changed to comply with the returnValues processing in the Java
// KSG CMI calc, which is different from the one in the MI calc.
result[0] = -1 * sumDigammas[0];
result[1] = -1;
result[2] = -1;
result[3] = -1;
result[4] = -1;
result[5] = -1;
}
}
stopTimer(pt);
}
err = JIDT_SUCCESS;
freeDeviceMemory(d_source);
return err;
}

30
cuda/gpuCMILibrary.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef GPUCMILIBRARY_H
#define GPUCMILIBRARY_H
#include "gpuKnnLibrary.h"
#define FREE(x) { if (x) free(x); x = NULL; }
#ifdef __cplusplus
extern "C" {
#endif
jidt_error_t CMIKraskovWithReorderings(int N, float *source, int dimx,
float *dest, int dimy, float *cond, int dimz,
int k, int thelier, int nb_surrogates, int returnLocals, int useMaxNorm,
int isAlgorithm1, float *result, int reorderingsGiven, int **reorderings,
int variableToReorder);
jidt_error_t CMIKraskov_C(int N, float *source, int dimx, float *dest, int dimy,
float *cond, int dimz, int k, int thelier, int nb_surrogates,
int returnLocals, int useMaxNorm, int isAlgorithm1, float *result,
int variableToReorder);
jidt_error_t CMIKraskovByPointsetChunks(int N, float *source, int dimx,
float *dest, int dimy, float *cond, int dimz, int k, int thelier, int nb_surrogates,
int returnLocals, int useMaxNorm, int isAlgorithm1, float *result, float *pointset);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -469,6 +469,26 @@ __global__ void gpuDigammas(float *g_digammas, int *g_nx, int *g_ny, int signall
}
__global__ void gpuDigammasCMI(float *g_digammas, int *g_nx, int *g_ny, int *g_nz, int signallength) {
const unsigned int i = threadIdx.x + blockDim.x*blockIdx.x;
if(i < signallength){
// Fetch n and put it in thread memory
double dgX = (double) g_nx[i];
double dgY = (double) g_ny[i];
double dgZ = (double) g_nz[i];
// In-place digamma calculation
digammaXp1(&dgX);
digammaXp1(&dgY);
digammaXp1(&dgZ);
// Copy back to global memory
g_digammas[i] = (float) (dgX + dgY - dgZ);
}
return;
}

View File

@ -57,6 +57,57 @@ int allocateDeviceMemory(int signalLength, int k, int dimx, int dimy,
return 1;
}
/**
* Allocate all necessary memory for the whole CMI calculation in a single call
* to cudaMalloc, and point the pointers to the right place.
*
* @param signalLength total number of samples given, including surrogates
* @param k nunmber of neighbours to find
* @param dimx dimension of source points
* @param dimy dimension of dest points
* @param dimz dimension of cond points
* @param source,dest,cond,distances,indexes,radii,nx,ny,nz,digammas device pointers
* @param pointset pointer to the data array in host memory
*
* @return error code
*/
int allocateDeviceMemoryCMI(int signalLength, int k, int dimx, int dimy, int dimz,
float **source, float **dest, float **cond, float **distances, int **indexes,
float **radii, int **nx, int **ny, int **nz, float **digammas, float *pointset) {
float *d_pointset;
int dims = dimx + dimy + dimz;
size_t mempointset = signalLength * dims * sizeof(float);
size_t memdistances = signalLength * k * sizeof(float);
size_t memindexes = signalLength * k * sizeof(int);
size_t memcounts = 3 * signalLength * sizeof(int);
size_t memdigammas = signalLength * sizeof(float);
size_t memtotal = mempointset + memdistances + memindexes + memcounts + memdigammas;
checkCudaErrors( cudaMalloc((void **) &d_pointset, memtotal) );
cudaError_t error = cudaGetLastError();
if(error!=cudaSuccess){
fprintf(stderr,"%s",cudaGetErrorString(error));
return 0;
}
checkCudaErrors( cudaMemcpy(d_pointset, pointset, mempointset, cudaMemcpyHostToDevice) );
*source = d_pointset;
*cond = *source + signalLength*dimx;
*dest = *cond + signalLength*dimz;
*distances = *dest + signalLength*dimy;
*radii = *distances + (k-1)*signalLength;
*indexes = (int *) (*distances + k*signalLength);
*nx = *indexes + signalLength;
*ny = *nx + signalLength;
*nz = *ny + signalLength;
*digammas = (float *) (*nz + signalLength);
return 1;
}
/**
* Free all the memory used in GPU (if allocated using allocateDeviceMemory.
*
@ -480,6 +531,26 @@ int d_parallelDigammas(float *digammas, float *d_digammas, int *d_nx,
}
int d_parallelDigammasCMI(float *digammas, float *d_digammas, int *d_nx,
int *d_ny, int *d_nz, int signalLength) {
// Kernel parameters
dim3 threads(1,1,1);
dim3 grid(1,1,1);
threads.x = 512;
grid.x = (signalLength-1)/threads.x + 1;
// Launch kernel
gpuDigammasCMI<<<grid.x, threads.x>>>(d_digammas, d_nx, d_ny, d_nz, signalLength);
checkCudaErrors( cudaDeviceSynchronize() );
checkCudaErrors( cudaMemcpy(digammas, d_digammas, signalLength * sizeof(float), cudaMemcpyDeviceToHost) );
checkCudaErrors( cudaDeviceSynchronize() );
return 1;
}
int parallelDigammas(float *digammas, int *nx, int *ny, int signalLength) {
int *d_nx, *d_ny;
@ -513,24 +584,12 @@ int parallelDigammas(float *digammas, int *nx, int *ny, int signalLength) {
return 1;
}
int d_cudaSumDigammas(float *sumDigammas, int *d_nx, int *d_ny,
float *d_digammas, int trialLength, int nchunks) {
int cudaBlockReduce(float *sumDigammas, float *d_digammas, int trialLength, int nchunks) {
float *d_sumDigammas;
int signalLength = trialLength * nchunks;
// Kernel parameters
dim3 threads(1,1,1);
dim3 grid(1,1,1);
threads.x = 512;
grid.x = (signalLength-1)/threads.x + 1;
checkCudaErrors( cudaMalloc((void **) &d_sumDigammas, nchunks * sizeof(int)) );
// Launch kernel to calculate (digamma(nx+1) + digamma(ny+1)), and leave
// results in GPU
gpuDigammas<<<grid.x, threads.x>>>(d_digammas, d_nx, d_ny, signalLength);
checkCudaErrors( cudaDeviceSynchronize() );
int offset_size = nchunks + 1;
int offsets[offset_size];
for (int i = 0; i < (nchunks+1); i++) { offsets[i] = i*trialLength; }
@ -558,6 +617,46 @@ int d_cudaSumDigammas(float *sumDigammas, int *d_nx, int *d_ny,
checkCudaErrors( cudaFree(d_sumDigammas) );
return 1;
}
int d_cudaSumDigammas(float *sumDigammas, int *d_nx, int *d_ny,
float *d_digammas, int trialLength, int nchunks) {
int signalLength = trialLength * nchunks;
// Kernel parameters
dim3 threads(1,1,1);
dim3 grid(1,1,1);
threads.x = 512;
grid.x = (signalLength-1)/threads.x + 1;
// Launch kernel to calculate (digamma(nx+1) + digamma(ny+1)), and leave
// results in GPU
gpuDigammas<<<grid.x, threads.x>>>(d_digammas, d_nx, d_ny, signalLength);
checkCudaErrors( cudaDeviceSynchronize() );
return cudaBlockReduce(sumDigammas, d_digammas, trialLength, nchunks);
}
int d_cudaSumDigammasCMI(float *sumDigammas, int *d_nx, int *d_ny, int *d_nz,
float *d_digammas, int trialLength, int nchunks) {
int signalLength = trialLength * nchunks;
// Kernel parameters
dim3 threads(1,1,1);
dim3 grid(1,1,1);
threads.x = 512;
grid.x = (signalLength-1)/threads.x + 1;
// Launch kernel to calculate (digamma(nx+1) + digamma(ny+1)), and leave
// results in GPU
gpuDigammasCMI<<<grid.x, threads.x>>>(d_digammas, d_nx, d_ny, d_nz, signalLength);
checkCudaErrors( cudaDeviceSynchronize() );
return cudaBlockReduce(sumDigammas, d_digammas, trialLength, nchunks);
}
/**
@ -594,6 +693,21 @@ void device_reset(void) {
void gpuWarmUp(void) {
cudaSetDevice(0);
}
/**
* Make random permutation of perm[].
*
* @param perm preallocated and prefilled integer array to be shuffled
* @param n number of elements in perm
*/
void randperm(int perm[], int n) {
// Random permutation the order
for (int i = 0; i < n; i++) {
int j, t;
j = rand() % (n-i) + i;
t = perm[j]; perm[j] = perm[i]; perm[i] = t; // Swap i and j
}
}
#ifdef __cplusplus
}
#endif

View File

@ -4,10 +4,16 @@
#ifdef __cplusplus
extern "C" {
#endif
typedef enum { JIDT_SUCCESS, JIDT_ERROR } jidt_error_t;
int allocateDeviceMemory(int signalLength, int kth, int dimx, int dimy,
float **source, float **dest, float **distances, int **indexes,
float **radii, int **nx, int **ny, float **digammas, float *pointset);
int allocateDeviceMemoryCMI(int signalLength, int k, int dimx, int dimy, int dimz,
float **source, float **dest, float **cond, float **distances, int **indexes,
float **radii, int **nx, int **ny, int **nz, float **digammas, float *pointset);
int freeDeviceMemory(float *d_pointset);
int cudaFindKnn(int* h_bf_indexes, float* h_bf_distances, float* h_pointset,
@ -47,12 +53,22 @@ int d_cudaFindRSAll(int* d_bf_npointsrange, float* d_bf_pointset, float* d_bf_qu
int d_parallelDigammas(float *digammas, float *d_digammas, int *d_nx,
int *d_ny, int signalLength);
int d_parallelDigammasCMI(float *digammas, float *d_digammas, int *d_nx,
int *d_ny, int *d_nz, int signalLength);
int cudaBlockReduce(float *sumDigammas, float *d_digammas, int trialLength, int nchunks);
int d_cudaSumDigammas(float *sumDigammas, int *d_nx, int *d_ny,
float *d_digammas, int trialLength, int nchunks);
int d_cudaSumDigammasCMI(float *sumDigammas, int *d_nx, int *d_ny, int *d_nz,
float *d_digammas, int trialLength, int nchunks);
void device_reset(void);
void gpuWarmUp(void);
void randperm(int perm[], int n);
#ifdef __cplusplus
}
#endif

View File

@ -8,22 +8,6 @@
#include "ctimer.h"
/**
* Make random permutation of perm[].
*
* @param perm preallocated and prefilled integer array to be shuffled
* @param n number of elements in perm
*/
void randperm(int perm[], int n) {
// Random permutation the order
for (int i = 0; i < n; i++) {
int j, t;
j = rand() % (n-i) + i;
t = perm[j]; perm[j] = perm[i]; perm[i] = t; // Swap i and j
}
}
jidt_error_t MIKraskov_C(int N, float *source, int dimx, float *dest, int dimy,
int k, int thelier, int nb_surrogates, int returnLocals, int useMaxNorm,
int isAlgorithm1, float *result) {

View File

@ -1,13 +1,13 @@
#ifndef GPUMILIBRARY_H
#define GPUMILIBRARY_H
#include "gpuKnnLibrary.h"
#define FREE(x) { if (x) free(x); x = NULL; }
#ifdef __cplusplus
extern "C" {
#endif
typedef enum { JIDT_SUCCESS, JIDT_ERROR } jidt_error_t;
jidt_error_t MIKraskovWithReorderings(int N, float *source, int dimx, float *dest, int dimy,
int k, int thelier, int nb_surrogates, int returnLocals, int useMaxNorm,
int isAlgorithm1, float *result, int reorderingsGiven, int **reorderings);
@ -20,8 +20,6 @@ jidt_error_t MIKraskovByPointsetChunks(int N, float *source, int dimx,
float *dest, int dimy, int k, int thelier, int nb_surrogates,
int returnLocals, int useMaxNorm, int isAlgorithm1, float *result,
float *pointset);
void randperm(int perm[], int n);
#ifdef __cplusplus
}
#endif

View File

@ -5,6 +5,7 @@
#define check(ans) { _check((ans), __FILE__, __LINE__); }
#include "gpuMILibrary.h"
#include "gpuCMILibrary.h"
#include "ctimer.h"
#ifdef __cplusplus
@ -196,6 +197,193 @@ JNIEXPORT jdoubleArray JNICALL
} // End of function MIKraskov
/*
* Class: infodynamics_measures_continuous_kraskov_ConditionalMutualInfoCalculatorMultiVariateKraskov
* Method: CMIKraskov
* Signature: (I[DI[DI[DIIIZZZIZ[II)[D
*/
JNIEXPORT jdoubleArray JNICALL
Java_infodynamics_measures_continuous_kraskov_ConditionalMutualInfoCalculatorMultiVariateKraskov_CMIKraskov(
JNIEnv *env, jobject thisObj, jint j_N,
jobjectArray j_sourceArray, jint j_dimx,
jobjectArray j_destArray, jint j_dimy,
jobjectArray j_condArray, jint j_dimz,
jint j_k, jint j_theiler, jboolean j_returnLocals,
jboolean j_useMaxNorm, jboolean j_isAlgorithm1, jint j_nbSurrogates,
jboolean j_reorderingsGiven, jobjectArray j_orderings,
jint j_variableToReorder) {
// Check that incoming data has correct size
// =====================
jsize sourceLength = (*env)->GetArrayLength(env, j_sourceArray);
jsize destLength = (*env)->GetArrayLength(env, j_destArray);
jsize condLength = (*env)->GetArrayLength(env, j_condArray);
// if (sourceLength != j_N || destLength != j_N || (j_N%(j_nbSurrogates+1) != 0)) {
if (sourceLength != j_N || destLength != j_N || condLength != j_N) {
jclass Exception = (*env)->FindClass(env, "java/lang/Exception");
(*env)->ThrowNew(env, Exception, "Data has wrong length.");
}
if (!j_isAlgorithm1) {
jclass Exception = (*env)->FindClass(env, "java/lang/Exception");
(*env)->ThrowNew(env, Exception, "Only algorithm 1 is supported.");
}
if ((j_returnLocals || !j_isAlgorithm1) && (j_nbSurrogates > 0)) {
jclass Exception = (*env)->FindClass(env, "java/lang/Exception");
(*env)->ThrowNew(env, Exception, "Surrogates only supported for average MI with KSG1.");
}
// Copy variables from Java
// =====================
int N = j_N;
int k = j_k;
int dimx = j_dimx;
int dimy = j_dimy;
int dimz = j_dimz;
int theiler = j_theiler;
int returnLocals = j_returnLocals ? 1 : 0;
int useMaxNorm = j_useMaxNorm ? 1 : 0;
int isAlgorithm1 = j_isAlgorithm1 ? 1 : 0;
int nb_surrogates = j_nbSurrogates;
int reorderingsGiven = j_reorderingsGiven ? 1 : 0;
int variableToReorder = j_variableToReorder;
CPerfTimer pt = startTimer("Java array copy");
float *source = (float *) malloc(N * dimx * sizeof(float));
float *dest = (float *) malloc(N * dimy * sizeof(float));
float *cond = (float *) malloc(N * dimz * sizeof(float));
if (NULL == source || NULL == dest || NULL == cond) {
jclass Exception = (*env)->FindClass(env, "java/lang/Exception");
(*env)->ThrowNew(env, Exception, "Error allocating data.");
}
for (int i = 0; i < N; i++) {
jdoubleArray j_sourceRow = (jdoubleArray) (*env)->GetObjectArrayElement(env, j_sourceArray, i);
jdoubleArray j_destRow = (jdoubleArray) (*env)->GetObjectArrayElement(env, j_destArray, i);
jdoubleArray j_condRow = (jdoubleArray) (*env)->GetObjectArrayElement(env, j_condArray, i);
jdouble *sourceRow = (*env)->GetDoubleArrayElements(env, j_sourceRow, NULL);
jdouble *destRow = (*env)->GetDoubleArrayElements(env, j_destRow, NULL);
jdouble *condRow = (*env)->GetDoubleArrayElements(env, j_condRow, NULL);
// Data in java are doubles, but GPUs need floats.
// We have to cast them manually, so we can't memcopy
// The following for-loops get two matrices in T-by-D indexing (i.e.
// first dimension is time, second is variable) and return the data in
// column-major form
for (int j = 0; j < dimx; j++) {
source[N*j + i] = (float) sourceRow[j];
}
for (int j = 0; j < dimy; j++) {
dest[N*j + i] = (float) destRow[j];
}
for (int j = 0; j < dimz; j++) {
cond[N*j + i] = (float) condRow[j];
}
(*env)->ReleaseDoubleArrayElements(env, j_sourceRow, sourceRow, 0);
(*env)->ReleaseDoubleArrayElements(env, j_destRow, destRow, 0);
(*env)->ReleaseDoubleArrayElements(env, j_condRow, condRow, 0);
(*env)->DeleteLocalRef(env, j_sourceRow);
(*env)->DeleteLocalRef(env, j_destRow);
(*env)->DeleteLocalRef(env, j_condRow);
// FIXME: I'm not entirely sure I'm freeing all the memory here. I should
// check for memory leaks more carefully.
}
int **reorderings = NULL;
if (reorderingsGiven) {
reorderings = (int **) malloc(nb_surrogates * sizeof(int *));
for (int i = 0; i < nb_surrogates; i++) {
jintArray j_order = (jdoubleArray) (*env)->GetObjectArrayElement(env, j_orderings, i);
jint *order = (*env)->GetIntArrayElements(env, j_order, NULL);
reorderings[i] = (int *) malloc(N * sizeof(int));
for (int j = 0; j < N; j++) {
reorderings[i][j] = order[j];
}
(*env)->ReleaseIntArrayElements(env, j_order, order, 0);
(*env)->DeleteLocalRef(env, j_order);
}
}
stopTimer(pt);
// Call C function
// =========================
int resultSize;
if (returnLocals) {
resultSize = N;
} else if (nb_surrogates > 0) {
resultSize = nb_surrogates + 1;
} else {
resultSize = 6;
}
float *result = (float *) malloc(resultSize * sizeof(float));
jidt_error_t ret;
if (!reorderingsGiven) {
ret = CMIKraskov_C(N, source, dimx, dest, dimy, cond, dimz,
k, theiler, nb_surrogates, returnLocals, useMaxNorm,
isAlgorithm1, result, variableToReorder);
} else {
ret = CMIKraskovWithReorderings(N, source, dimx, dest, dimy, cond, dimz, k, theiler,
nb_surrogates, returnLocals, useMaxNorm,
isAlgorithm1, result, reorderingsGiven,
reorderings, variableToReorder);
}
if (JIDT_ERROR == ret) {
jclass Exception = (*env)->FindClass(env, "java/lang/Exception");
(*env)->ThrowNew(env, Exception, "Error in GPU execution.");
}
// Free memory and return
// =========================
if (source) free(source);
if (dest) free(dest);
if (cond) free(cond);
if (reorderingsGiven) {
for (int i = 0; i < nb_surrogates; i++) {
if (reorderings[i]) free(reorderings[i]);
}
if (reorderings) free (reorderings);
}
jdouble outCArray[resultSize];
for (int i = 0; i < resultSize; i++) {
outCArray[i] = result[i];
}
// Set Java array for return
jdoubleArray outJNIArray = (*env)->NewDoubleArray(env, resultSize); // allocate
if (NULL == outJNIArray) {
jclass Exception = (*env)->FindClass(env, "java/lang/Exception");
(*env)->ThrowNew(env, Exception, "Error creating return array.");
}
(*env)->SetDoubleArrayRegion(env, outJNIArray, 0 , resultSize, outCArray); // copy
if (result) { free(result); }
return outJNIArray;
} // End of function CMIKraskov
#ifdef __cplusplus
}
#endif

View File

@ -5,6 +5,7 @@
#include "gpuKnnLibrary.h"
#include "gpuMILibrary.h"
#include "gpuCMILibrary.h"
#include "digamma.h"
using lest::approx;
@ -606,6 +607,46 @@ CASE("Test correct pointset arrangement without reorderings")
EXPECT(result1[2] == approx(result2[2]));
},
CASE("Test correct pointset arrangement without reorderings in CMI")
{
int N = 10;
int dimx = 1;
int dimy = 1;
int dimz = 1;
int k = 2;
int thelier = 0;
int returnLocals = 0;
int useMaxNorm = 1;
int isAlgorithm1 = 1;
float source[10] = {0.4, 1, -4, 1, 1, 0.2, 98, 12, 1.2, 1.3};
float dest[10] = { -3, 1, 3, -2, 2.1, 8.5, 4.2, 100, 12, 0};
float cond[10] = { -1, 4, 3, -8, 0.3, 2.1, 3.2, 111, 32, 7};
float pointset[30] = {0.4, 1, -4, 1, 1, 0.2, 98, 12, 1.2, 1.3,
-1, 4, 3, -8, 0.3, 2.1, 3.2, 111, 32, 7,
-3, 1, 3, -2, 2.1, 8.5, 4.2, 100, 12, 0};
float result1[6];
float result2[6];
jidt_error_t err;
err = CMIKraskov_C(N, source, dimx, dest, dimy, cond, dimz, k, thelier,
0, returnLocals, useMaxNorm, isAlgorithm1, result1, 1);
EXPECT(err == JIDT_SUCCESS);
err = CMIKraskovByPointsetChunks(N, source, dimx, dest, dimy, cond, dimz, k, thelier,
1, returnLocals, useMaxNorm, isAlgorithm1, result2, pointset);
EXPECT(err == JIDT_SUCCESS);
EXPECT(result1[0] == approx(result2[0]));
EXPECT(result1[1] == approx(result2[1]));
EXPECT(result1[2] == approx(result2[2]));
EXPECT(result1[3] == approx(result2[3]));
EXPECT(result1[4] == approx(result2[4]));
EXPECT(result1[5] == approx(result2[5]));
},
CASE("Test correct pointset arrangement in more than one dimension")
{
int N = 5;
@ -654,6 +695,67 @@ CASE("Test correct pointset arrangement in more than one dimension")
EXPECT(result1[2] == approx(result2[2]));
},
CASE("Test correct pointset arrangement in more than one dimension for CMI")
{
int N = 5;
int dimx = 2;
int dimy = 2;
int dimz = 2;
int k = 2;
int thelier = 0;
int returnLocals = 0;
int useMaxNorm = 1;
int isAlgorithm1 = 1;
// Source points: X Y
// 0.4 0.2
// 1 98
// -4 12
// 1 1.2
// 1 1.3
//
// Dest points: X Y
// -3 8.5
// 1 4.2
// 3 100
// -2 12
// 2.1 0
//
// Cond points: X Y
// -1 2.1
// 4 3.2
// 3 111
// -8 32
// 0.3 7
float source[10] = {0.4, 1, -4, 1, 1, 0.2, 98, 12, 1.2, 1.3};
float dest[10] = { -3, 1, 3, -2, 2.1, 8.5, 4.2, 100, 12, 0};
float cond[10] = { -1, 4, 3, -8, 0.3, 2.1, 3.2, 111, 32, 7};
float pointset[30] = {0.4, 1, -4, 1, 1, 0.2, 98, 12, 1.2, 1.3,
-1, 4, 3, -8, 0.3, 2.1, 3.2, 111, 32, 7,
-3, 1, 3, -2, 2.1, 8.5, 4.2, 100, 12, 0};
float result1[6];
float result2[6];
jidt_error_t err;
err = CMIKraskov_C(N, source, dimx, dest, dimy, cond, dimz, k, thelier,
0, returnLocals, useMaxNorm, isAlgorithm1, result1, 1);
EXPECT(err == JIDT_SUCCESS);
err = CMIKraskovByPointsetChunks(N, source, dimx, dest, dimy, cond, dimz, k, thelier,
1, returnLocals, useMaxNorm, isAlgorithm1, result2, pointset);
EXPECT(err == JIDT_SUCCESS);
EXPECT(result1[0] == approx(result2[0]));
EXPECT(result1[1] == approx(result2[1]));
EXPECT(result1[2] == approx(result2[2]));
EXPECT(result1[3] == approx(result2[3]));
EXPECT(result1[4] == approx(result2[4]));
EXPECT(result1[5] == approx(result2[5]));
},
CASE("Test that same sample in repeated chunks gives same result")
{
int N = 5;
@ -691,6 +793,46 @@ CASE("Test that same sample in repeated chunks gives same result")
},
CASE("Test that same sample in repeated chunks gives same result in CMI")
{
int N = 5;
int dimx = 1;
int dimy = 1;
int dimz = 1;
// Sample source and dest data
float source[5] = {0.4, 1, -4, 1, 1};
float dest[5] = { -3, 1, 3, -2, 2.1};
float cond[5] = { -1, 4, 3, -8, 0.3};
// Pointset with source and dest repeated twice
float double_pointset[30] = {0.4, 1, -4, 1, 1, 0.4, 1, -4, 1, 1,
-1, 4, 3, -8, 0.3, -1, 4, 3, -8, 0.3,
-3, 1, 3, -2, 2.1, -3, 1, 3, -2, 2.1};
int k = 2;
int thelier = 0;
int returnLocals = 0;
int useMaxNorm = 1;
int isAlgorithm1 = 1;
float result1[3];
float result2[2];
jidt_error_t err;
err = CMIKraskov_C(N, source, dimx, dest, dimy, cond, dimz, k, thelier,
0, returnLocals, useMaxNorm, isAlgorithm1, result1, 1);
err = CMIKraskovByPointsetChunks(N*2, source, dimx, dest, dimy, cond, dimz, k, thelier,
2, returnLocals, useMaxNorm, isAlgorithm1, result2, double_pointset);
float CMI1 = cpuDigamma(k) + result1[0]/((double) N);
EXPECT(err == JIDT_SUCCESS);
EXPECT(result2[0] == approx(CMI1));
EXPECT(result2[0] == approx(result2[1]));
},
CASE("Test that same sample of 2D data in repeated chunks gives same result")
{
int N = 5;
@ -763,13 +905,39 @@ CASE("Test that sample and identity reordering have same MI")
int **reorderings = &order_p;
jidt_error_t err;
printf("====================================\n");
err = MIKraskovWithReorderings(N, source, dimx, dest, dimy, k, thelier,
1, returnLocals, useMaxNorm, isAlgorithm1, result, reorderingsGiven, reorderings);
EXPECT(err == JIDT_SUCCESS);
EXPECT(result[0] == approx(result[1]));
printf("Test results: %f\t%f\n", result[0], result[1]);
},
CASE("Test that sample and identity reordering have same CMI")
{
int N = 5;
int dimx = 1;
int dimy = 1;
int dimz = 1;
float source[5] = {0.4, 1, -4, 1, 1};
float dest[5] = { -3, 1, 3, -2, 2.1};
float cond[5] = { -1, 4, 3, -8, 0.3};
int k = 2;
int thelier = 0;
int returnLocals = 0;
int useMaxNorm = 1;
int isAlgorithm1 = 1;
float result[2];
int reorderingsGiven = 1;
int order[5] = {0, 1, 2, 3, 4};
int *order_p = order;
int **reorderings = &order_p;
jidt_error_t err;
err = CMIKraskovWithReorderings(N, source, dimx, dest, dimy, cond, dimz, k, thelier,
1, returnLocals, useMaxNorm, isAlgorithm1, result, reorderingsGiven, reorderings, 1);
EXPECT(err == JIDT_SUCCESS);
EXPECT(result[0] == approx(result[1]));
},
@ -808,7 +976,6 @@ CASE("Test identity reordering with more than one dimension")
int **reorderings = &order_p;
jidt_error_t err;
printf("====================================\n");
err = MIKraskovWithReorderings(N, source, dimx, dest, dimy, k, thelier,
0, returnLocals, useMaxNorm, isAlgorithm1, result1, reorderingsGiven, reorderings);
@ -818,8 +985,6 @@ CASE("Test identity reordering with more than one dimension")
1, returnLocals, useMaxNorm, isAlgorithm1, result2, reorderingsGiven, reorderings);
EXPECT(err == JIDT_SUCCESS);
printf("Test results: %f\t%f\n", result2[0], result2[1]);
EXPECT(result2[0] == approx(result2[1]));
},
@ -849,15 +1014,12 @@ CASE("Test identity reordering with larger dataset")
float result[2];
jidt_error_t err;
printf("====================================\n");
err = MIKraskovWithReorderings(N, source, dimx, dest, dimy, k, thelier,
1, returnLocals, useMaxNorm, isAlgorithm1, result, reorderingsGiven, reorderings);
free(source); free(dest); free(order);
EXPECT(err == JIDT_SUCCESS);
printf("Test results: %f\t%f\n", result[0], result[1]);
EXPECT(result[0] == approx(result[1]));
},
@ -899,13 +1061,10 @@ CASE("Test non-identity reordering in 2D")
float result[2];
jidt_error_t err;
printf("====================================\n");
err = MIKraskovWithReorderings(N, source, dimx, dest, dimy, k, thelier,
1, returnLocals, useMaxNorm, isAlgorithm1, result, reorderingsGiven, reorderings);
EXPECT(err == JIDT_SUCCESS);
printf("Test results: %f\t%f\n", result[0], result[1]);
EXPECT(result[0] != approx(result[1]));
},
@ -931,15 +1090,12 @@ CASE("Test random surrogates in 2D")
float result[3];
jidt_error_t err;
printf("====================================\n");
err = MIKraskov_C(N, source, dimx, dest, dimy, k, thelier,
2, returnLocals, useMaxNorm, isAlgorithm1, result);
free(source); free(dest);
EXPECT(err == JIDT_SUCCESS);
printf("Test results: %f\t%f\n", result[0], result[1]);
EXPECT(result[0] != result[1]);
EXPECT(result[0] != result[2]);
EXPECT(result[1] != result[2]);
@ -978,20 +1134,74 @@ CASE("Test that the first result of calculation with surrogates is the same as w
float result2[2];
jidt_error_t err;
printf("====================================\n");
err = MIKraskov_C(N, source, dimx, dest, dimy, k, thelier,
0, returnLocals, useMaxNorm, isAlgorithm1, result1);
EXPECT(err == JIDT_SUCCESS);
float MI1 = cpuDigamma(k) + cpuDigamma(N) - result1[0]/((double) N);
printf("====================================\n");
err = MIKraskov_C(N, source, dimx, dest, dimy, k, thelier,
1, returnLocals, useMaxNorm, isAlgorithm1, result2);
EXPECT(err == JIDT_SUCCESS);
EXPECT(MI1 == approx(result2[0]));
EXPECT(result2[0] != result2[1]);
},
CASE("Test that the first result of calculation with surrogates is the same as without in CMI")
{
int thelier = 0;
int useMaxNorm = 1;
int N = 10;
int dimx = 1;
int dimy = 1;
int dimz = 1;
int k = 2;
int isAlgorithm1 = 1;
int returnLocals = 0;
// Source points: X Y Z
// 0.4 0.2 0
// 1 98 13
// -4 12 7
// 1 1.2 -1
// 1 1.3 0
//
// Dest points: X Y
// -3 8.5
// 1 4.2
// 3 100
// -2 13
// 2.1 0
//
// Cond points: X Y
// -1 2.1
// 4 3.2
// 3 111
// -8 32
// 0.3 7
float source[15] = {0.4, 1, -4, 1, 1, 0.2, 98, 12, 1.2, 1.3, 0, 13, 7, -1, 0};
float dest[10] = { -3, 1, 3, -2, 2.1, 8.5, 4.2, 100, 13, 0};
float cond[10] = { -1, 4, 3, -8, 0.3, 2.1, 3.2, 111, 32, 7};
float result1[6];
float result2[2];
jidt_error_t err;
err = CMIKraskov_C(N, source, dimx, dest, dimy, cond, dimz, k, thelier,
0, returnLocals, useMaxNorm, isAlgorithm1, result1, 1);
EXPECT(err == JIDT_SUCCESS);
printf("No surrogates: %f, with 1 surrogate: %f, %f\n", MI1, result2[0], result2[1]);
EXPECT(MI1 == approx(result2[0]));
float CMI1 = cpuDigamma(k) + result1[0]/((double) N);
err = CMIKraskov_C(N, source, dimx, dest, dimy, cond, dimz, k, thelier,
1, returnLocals, useMaxNorm, isAlgorithm1, result2, 1);
EXPECT(err == JIDT_SUCCESS);
EXPECT(CMI1 == approx(result2[0]));
EXPECT(result2[0] != result2[1]);
},

View File

@ -0,0 +1,8 @@
% Launch the AutoAnalyser from within Matlab. You will need to have Matlab open at the demos/AutoAnalyser folder.
% This is useful where you don't have a separate Java Runtime Environment installed, and so utilise Matlab's
warning('off','MATLAB:Java:DuplicateClass');
javaaddpath('../../infodynamics.jar');
autoAnalyser = javaObject('infodynamics.demos.autoanalysis.AutoAnalyserLauncher', false);
fprintf('Be warned - closing the AutoAnalyser applet seems to close Matlab completely, so only do so when ready to exit Matlab!\n');

View File

@ -0,0 +1,11 @@
from jpype import *
# Add JIDT jar library to the path
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)
# Construct an AutoAnalyser
calcClass = JPackage("infodynamics.demos.autoanalysis").AutoAnalyserLauncher
calc = calcClass(False)

View File

@ -1,5 +0,0 @@
@ECHO OFF
REM Run the example:
java -classpath "..\..\infodynamics.jar" infodynamics.demos.autoanalysis.AutoAnalyserAIS

View File

@ -1,5 +0,0 @@
#!/bin/bash
# Run the example:
java -classpath "../../infodynamics.jar" infodynamics.demos.autoanalysis.AutoAnalyserAIS

View File

@ -1,5 +0,0 @@
@ECHO OFF
REM Run the example:
java -classpath "..\..\infodynamics.jar" infodynamics.demos.autoanalysis.AutoAnalyserCMI

View File

@ -1,5 +0,0 @@
#!/bin/bash
# Run the example:
java -classpath "../../infodynamics.jar" infodynamics.demos.autoanalysis.AutoAnalyserCMI

View File

@ -1,5 +0,0 @@
@ECHO OFF
REM Run the example:
java -classpath "..\..\infodynamics.jar" infodynamics.demos.autoanalysis.AutoAnalyserCTE

View File

@ -1,5 +0,0 @@
#!/bin/bash
# Run the example:
java -classpath "../../infodynamics.jar" infodynamics.demos.autoanalysis.AutoAnalyserCTE

View File

@ -1,5 +0,0 @@
@ECHO OFF
REM Run the example:
java -classpath "..\..\infodynamics.jar" infodynamics.demos.autoanalysis.AutoAnalyserEntropy

View File

@ -1,5 +0,0 @@
#!/bin/bash
# Run the example:
java -classpath "../../infodynamics.jar" infodynamics.demos.autoanalysis.AutoAnalyserEntropy

View File

@ -1,5 +0,0 @@
@ECHO OFF
REM Run the example:
java -classpath "..\..\infodynamics.jar" infodynamics.demos.autoanalysis.AutoAnalyserMI

View File

@ -1,5 +0,0 @@
#!/bin/bash
# Run the example:
java -classpath "../../infodynamics.jar" infodynamics.demos.autoanalysis.AutoAnalyserMI

View File

@ -1,5 +0,0 @@
@ECHO OFF
REM Run the example:
java -classpath "..\..\infodynamics.jar" infodynamics.demos.autoanalysis.AutoAnalyserTE

View File

@ -1,5 +0,0 @@
#!/bin/bash
# Run the example:
java -classpath "../../infodynamics.jar" infodynamics.demos.autoanalysis.AutoAnalyserTE

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

0
demos/java/example10GPUBenchmark.sh Normal file → Executable file
View File

View File

@ -67,9 +67,10 @@ public class Example10GPUBenchmark {
miCalc.setProperty("k", "4");
miCalc.initialise(src[0].length, tgt[0].length);
miCalc.setObservations(src, tgt);
int nb_surrogates = 150;
double[] timeAndValue = new double[2];
long startTime = System.nanoTime();
timeAndValue[1] = miCalc.computeAverageLocalOfObservations();
timeAndValue[1] = miCalc.computeSignificance(nb_surrogates).actualValue;
timeAndValue[0] = (System.nanoTime() - startTime)/1000000.0;
return timeAndValue;
}

View File

@ -45,6 +45,7 @@
% - measureParams.j - we measure information transfer across j cells to the right per time step
% - options - a stucture containing a range of other options, i.e.:
% - plotOptions - structure as defined for the plotLocalInfoValues function
% - plotOptions.figNum - figure number to plot the info value profile in
% - seed - state for the random number generator used to set the initial condition of the CA (use this
% for reproducibility of plots, or to produce profiles for several different measures of the same CA raw states).
% We set rand('state', options.seed) if options.seed is supplied, and restore the previous seed afterwards.
@ -107,7 +108,11 @@ function [caStates, localValues] = plotLocalInfoMeasureForCA(neighbourhood, base
printDriver = options.saveImagesFormat;
fontSize = 13;
end
figNum = 2;
if (not(isfield(options.plotOptions, 'figNum')))
figNum = 2;
else
figNum = options.plotOptions.figNum;
end
toc
% The offsets of the parents (see runCA for how this is computed, especially for even neighbourhood):
fullSetOfParents = ceil(-neighbourhood / 2) : ceil(-neighbourhood / 2) + (neighbourhood-1);

View File

@ -176,7 +176,11 @@ function h = plotLocalInfoValues(localResults, plotOptions)
bluemap = prepareColourmap(mainSignVectorLength, true, scalingMainComponent, scalingScdryComponent, gammaPower);
colormap(bluemap);
% Now, plot the local values with the pre-prepared colormap
h = imagesc(localResultsToPlot, [0, maxLocal]);
if (maxLocal == 0)
h = imagesc(localResultsToPlot, [0, 1]);
else
h = imagesc(localResultsToPlot, [0, maxLocal]);
end
end
axis([0.5 (plotOptions.plotCols+0.5) 0.5 (plotOptions.plotRows+0.5)]);
colorbar

View File

@ -46,17 +46,24 @@
% - debug - turn on various debug messages
% - seedOrState (optional) - if a scalar, it is the state input for the random number generator (so one can repeat CA investigations for the same initial state).
% - if a vector, it is the initial state for the CA (must be of length cells)
% - alterProbability (optional, default 0) - defines stochastic probability of altering the value in the update of any given cell
%
% Outputs:
% - caStates - a run, from random initial conditions, of a CA of the given parameters.
% - ruleTable - the lookup table for each neighbourhood configuration, constructed from the rule number
% - executedRules - which CA rule was executed for every cell update that occurred for the CA.
function [caStates, ruleTable, executedRules] = runCA(neighbourhood, base, rule, cells, steps, debug, seedOrState)
function [caStates, ruleTable, executedRules] = runCA(neighbourhood, base, rule, cells, steps, debug, seedOrState, alterProbability)
% Check arguments:
ca = [];
if (nargin >= 7)
if (nargin < 8) || isempty(alterProbability)
alterProbability = 0;
end
if (nargin < 7)
seedOrState = [];
end
if (~isempty(seedOrState))
if (isscalar(seedOrState))
% User has supplied seed for the random number generator:
fprintf('Generating initial random CA state from seed %d\n', seedOrState);
@ -72,13 +79,13 @@ function [caStates, ruleTable, executedRules] = runCA(neighbourhood, base, rule,
else
fprintf('Generating initial random CA state\n');
end
if (nargin < 6)
if (nargin < 6) || isempty(debug)
debug = false;
end
if (nargin < 5)
if (nargin < 5) || isempty(steps)
steps = 100;
end
if (nargin < 4)
if (nargin < 4) || isempty(cells)
cells = 100;
end
if (nargin < 3)
@ -205,6 +212,19 @@ function [caStates, ruleTable, executedRules] = runCA(neighbourhood, base, rule,
% Need to add 1 to the ruleToRun because of the indexing starting from 1 not 0.
ca = ruleTable(ruleToRun + 1)';
% Check whether any of the CA states should be altered
if (alterProbability > 0)
% Could code this in a faster way, but won't matter too much
for c = 1 : cells
if (rand() < alterProbability)
% Alter this cell
chooseFrom = 0:(base-1);
chooseFrom(ca(c)+1) = []; % Remove the current value as an option so that we change this one
ca(c) = chooseFrom(randsample(length(chooseFrom), 1));
end
end
end
if (debug)
ca
end

View File

@ -0,0 +1,357 @@
%%%%%%%%%%%%%%%%%%%%
% Copyright (C) 2021, Joseph T. Lizier
% Distributed under GNU General Public License v3
%
% Infer the parent source variables to a given target, using the greedy/iterative/multivariate algorithm with TE.
% This a simplistic implementation of the full algorithm implemented in IDTxl - https://github.com/pwollstadt/idtxl -
% you are referred to IDTxl for an implementation with full features available.
%
% Inputs:
% - data: multivariate data, indexed by time,variableNumber, and possibly trialNumber.
% - parameters: an object containing the expected properties, or a string
% describing the filename to run load this object in. Can include:
% - parameters.calcType: which estimator type to use, from options
% 'discrete', 'gaussian', 'ksg', 'granger' --
% granger is equivalent to gaussian, but performed with Oliver Cliff's
% toolkit, to include proper autocorrelation correction.
% - parameters.timePointsToSkipAtStart: number of time points we'll skip
% at the start (default 0)
% - parameters.timePointsToSkipAtEnd: number of time points we'll skip
% at the end (default 0)
% - parameters.numDiscreteBins: alphabet size for the discrete variables when used. (default 2)
% - parameters.k: target embedding length, can be 'auto' to indicate auto-embedding (default 1)
% - parameters.k_max: max target embedding length to use when parameters.k == 'auto' (default 10)
% - parameters.numSurrogates: number of surrogates to run, or 0 for analytic surrogates (default 1000)
% - parameters.maxDynCorrExclLags: maximum length of dynamic correlation exclusion, which will be auto-fitted (default 50)
% - parameters.jidtLocation: path to the JIDT folder
% - parameters.gcToolkitLocation: Oliver's toolkit location for Granger
% - parameters.debug: whether to print debugging results as parents are inferred (default true)
% - targetIndex: which column number to run the inference for
% - uncorrectedThresholdForOneTarget: p-value threshold (where 0 is most significant) to select sources. We will Bonferroni correct this over sources here (but user should correct over targets if they wish)
function [parentSet, results, pValues, otherResults] = greedyInferParents(data, parameters, targetIndex, uncorrectedThresholdForOneTarget)
tic
if ischar(parameters)
% Assume that this string contains a filename which when run will load
% a properties object for this run
eval(['run ', parameters]);
end
% Add JIDT jar library to the path, and disable warnings that it's already there:
warning('off','MATLAB:Java:DuplicateClass');
%javaaddpath('/home/joseph/temp/jidt-master/jidt/infodynamics.jar');
javaaddpath([parameters.jidtLocation, 'infodynamics.jar']);
% Add utilities to the path
% addpath('/home/joseph/temp/jidt-master/jidt/demos/octave');
addpath([parameters.jidtLocation, 'demos/octave']);
% Add Oliver Cliff's toolkit to path
addpath(genpath(parameters.gcToolkitLocation));
% Set parameter defaults:
if ~isfield(parameters, 'numDiscreteBins')
parameters.numDiscreteBins = 2;
end
if ~isfield(parameters, 'k')
parameters.k = 1;
end
if ~isfield(parameters, 'k_max')
parameters.k_max = 10;
end
if ~isfield(parameters, 'numSurrogates')
parameters.numSurrogates = 1000;
end
if ~isfield(parameters, 'verbose')
parameters.verbose = true;
end
if ~isfield(parameters, 'timePointsToSkipAtStart')
parameters.timePointsToSkipAtStart = 0;
end
if ~isfield(parameters, 'timePointsToSkipAtEnd')
parameters.timePointsToSkipAtEnd = 0;
end
if ~isfield(parameters, 'maxDynCorrExclLags')
parameters.maxDynCorrExclLags = 50;
end
T = size(data,1); % TIMEPOINTS
N = size(data,2); % NODES
hasMultipleTrials = (length(size(data)) > 2);
if (hasMultipleTrials)
R = size(data,3); % TRIALS
% Analyse data(time, variables), but skip the first
% and last few steps
data = data(parameters.timePointsToSkipAtStart+1:end-parameters.timePointsToSkipAtEnd,:,:);
else
% Analyse data(time, variables), but skip the first
% and last few steps
data = data(parameters.timePointsToSkipAtStart+1:end-parameters.timePointsToSkipAtEnd,:);
end
threshold = uncorrectedThresholdForOneTarget / (N-1); % Bonferroni correcting the threshold
parentSet = [];
pValues = [];
results = [];
otherResults.k_history = 1;
candidates = [1:targetIndex-1, targetIndex+1:N]; % All sources except the targets are candidates as parents
% Set boolean flags for which calculator we are doing
is_jidt = true;
is_discrete = false;
is_ksg= false;
javaConverterSingleArray = 'octaveToJavaDoubleArray';
javaConverterMatrix = 'octaveToJavaDoubleMatrix';
if (strcmp(parameters.calcType, 'granger'))
is_jidt = false;
if (~ischar(parameters.k))
% if (ischar(parameters.k) && ~strcmp(parameters.k, 'auto')) % I don't think this logic was correct
parameters.k = char(string(parameters.k));
end
if (hasMultipleTrials)
error('Granger calculator does not currently support multiple trials');
end
elseif (strcmp(parameters.calcType, 'discrete'))
is_discrete = true;
javaConverterSingleArray = 'octaveToJavaIntArray';
javaConverterMatrix = 'octaveToJavaIntMatrix';
elseif (strcmp(parameters.calcType, 'ksg'))
is_ksg = true;
end
acfDecayTimes = -1 * ones(N,1);
% Grab the ACF decay time for the target
if (is_jidt)
if (~hasMultipleTrials)
acfDecayTimes(targetIndex) = computeAcfDecayTime(data(:, targetIndex), parameters);
else
acfDecayTimes(targetIndex) = computeAcfDecayTime(squeeze(data(:, targetIndex, :)), parameters);
end
k_history = parameters.k;
end
if (parameters.verbose)
fprintf('Beginning greedy selection of parents for %d with threshold %.6f\n', targetIndex, threshold);
end
% LOOP 1 -- iterating over rounds of source selection
while ~isempty(candidates)
% Whilst there are other candidates left (and we haven't quit)
% Construct the calculator and set properties:
if (is_jidt)
if (isempty(parentSet))
% Just doing pairwise TEs this round
if (is_discrete)
if (ischar(k_history)) % assume is 'auto'
error('Autoembedding not supported for discrete calculator at the moment');
end
calc = javaObject('infodynamics.measures.discrete.TransferEntropyCalculatorDiscrete', parameters.numDiscreteBins, k_history);
else
if (is_ksg)
calc = javaObject('infodynamics.measures.continuous.kraskov.TransferEntropyCalculatorKraskov');
else
calc = javaObject('infodynamics.measures.continuous.gaussian.TransferEntropyCalculatorGaussian');
end
if (ischar(k_history)) % assume is 'auto'
calc.setProperty('AUTO_EMBED_METHOD', 'MAX_CORR_AIS_DEST_ONLY');
calc.setProperty('AUTO_EMBED_K_SEARCH_MAX', string(parameters.k_max));
else
calc.setProperty('k_HISTORY', string(k_history));
end
end
else
% We're doing conditional TEs this round, conditioned on
% length(parentSet) other sources
if (is_discrete)
calc = javaObject('infodynamics.measures.discrete.ConditionalTransferEntropyCalculatorDiscrete', parameters.numDiscreteBins, k_history, length(parentSet));
else
if (is_ksg)
calc = javaObject('infodynamics.measures.continuous.kraskov.ConditionalTransferEntropyCalculatorKraskov');
else
calc = javaObject('infodynamics.measures.continuous.gaussian.ConditionalTransferEntropyCalculatorGaussian');
end
% Assume we have saved the relevant k after the first pairwise calculation
calc.setProperty('k_HISTORY', string(k_history));
% Set up the correct number of conditionals
calc.setProperty(calc.COND_EMBED_LENGTHS_PROP_NAME, strjoin(string(ones(length(parentSet), 1)), ','));
calc.setProperty(calc.COND_EMBED_DELAYS_PROP_NAME, strjoin(string(ones(length(parentSet), 1)), ','));
calc.setProperty(calc.COND_DELAYS_PROP_NAME, strjoin(string(ones(length(parentSet), 1)), ','));
end
end
if (~hasMultipleTrials)
destination = feval(javaConverterSingleArray, data(:, targetIndex));
conditionals = feval(javaConverterMatrix, data(:, parentSet));
end
else
destination = data(:, targetIndex);
conditionals = data(:, parentSet);
end
thisRoundTEResults = zeros(1, length(candidates));
thisRoundpValResults = zeros(1, length(candidates)); % Only used for Granger
% LOOP 2 -- checking (conditional) TE from all current candidates,
% given current parent set
for sIndexInCandidates = 1:length(candidates)
% For each candidate:
if is_jidt
if (acfDecayTimes(candidates(sIndexInCandidates)) < 0)
% We haven't computed the ACF decay time for this source yet
if (~hasMultipleTrials)
acfDecayTimes(candidates(sIndexInCandidates)) = ...
computeAcfDecayTime(data(:,candidates(sIndexInCandidates)), parameters);
else
acfDecayTimes(candidates(sIndexInCandidates)) = ...
computeAcfDecayTime(squeeze(data(:,candidates(sIndexInCandidates),:)), parameters);
end
end
if is_ksg
calc.setProperty('DYN_CORR_EXCL', num2str(max(acfDecayTimes([targetIndex,candidates(sIndexInCandidates),parentSet]))));
end
% 3. Initialise the calculator for (re-)use:
calc.initialise();
% 4. Supply the sample data:
calc.setDebug(true);
if (~hasMultipleTrials)
sourceTimeSeries = feval(javaConverterSingleArray, data(:, candidates(sIndexInCandidates)));
if (isempty(parentSet))
calc.setObservations(sourceTimeSeries, destination);
else
calc.setObservations(sourceTimeSeries, destination, conditionals);
end
else
calc.startAddObservations();
for numTrial = 1 : R
destination = feval(javaConverterSingleArray, squeeze(data(:, targetIndex, numTrial)));
conditionals = feval(javaConverterMatrix, squeeze(data(:, parentSet, numTrial)));
sourceTimeSeries = feval(javaConverterSingleArray, squeeze(data(:, candidates(sIndexInCandidates),numTrial)));
if (isempty(parentSet))
calc.addObservations(sourceTimeSeries, destination);
else
calc.addObservations(sourceTimeSeries, destination, conditionals);
end
end
calc.finaliseAddObservations();
end
calc.setDebug(false);
% 5. Compute the estimate:
result = calc.computeAverageLocalOfObservations();
thisRoundTEResults(sIndexInCandidates) = result;
if ischar(k_history)
k_history = calc.getProperty('k_HISTORY');
% We autoembedded the target history if we were going to - now grab the
% determined value to use next time
calc.setProperty('AUTO_EMBED_METHOD', 'NONE');
fprintf('Target history embedding set to %s\n', k_history);
end
otherResults.k_history = k_history;
else
% Compute Granger via Oliver's toolkit:
sourceTimeSeries = data(:, candidates(sIndexInCandidates));
[result,pval] = mvgc(destination,sourceTimeSeries,conditionals, ...
'p',parameters.k,'q','1','test','modified','surrogates',parameters.numSurrogates);
thisRoundTEResults(sIndexInCandidates) = result;
thisRoundpValResults(sIndexInCandidates) = pval;
% TODO need to readout the k history here
end
end
% Find the strongest source out of these candidates:
if is_jidt
[maxTE, maxIndex] = max(thisRoundTEResults);
else
% pval is higher for more significant. We will use this to
% determine the source selection, since it corrects the raw
% measure values for autocorrelation in this toolkit
[pValue, maxIndex] = max(thisRoundpValResults);
maxTE = thisRoundTEResults(maxIndex);
end
strongestSource = candidates(maxIndex);
% fprintf('Strongest source is %d with TE %.5f\n', strongestSource, maxTE);
% Check significance of this source (first need to set up its calculator again):
if is_jidt
calc.initialise();
if (~hasMultipleTrials)
sourceTimeSeries = feval(javaConverterSingleArray, data(:, strongestSource));
if (isempty(parentSet))
calc.setObservations(sourceTimeSeries, destination);
else
calc.setObservations(sourceTimeSeries, destination, conditionals);
end
else
calc.startAddObservations();
for numTrial = 1 : R
destination = feval(javaConverterSingleArray, squeeze(data(:, targetIndex, numTrial)));
conditionals = feval(javaConverterMatrix, squeeze(data(:, parentSet, numTrial)));
sourceTimeSeries = feval(javaConverterSingleArray, squeeze(data(:, strongestSource, numTrial)));
if (isempty(parentSet))
calc.addObservations(sourceTimeSeries, destination);
else
calc.addObservations(sourceTimeSeries, destination, conditionals);
end
end
calc.finaliseAddObservations();
end
maxTE = calc.computeAverageLocalOfObservations();
if (parameters.numSurrogates == 0)
measDist = calc.computeSignificance();
else
measDist = calc.computeSignificance(parameters.numSurrogates);
end
pValue = 1 - measDist.pValue; % Complementing the p value so it's the proportion of null the measure is greater than
end
if (pValue > 1 - threshold)
% We add this source to the parent set
if (parameters.verbose)
fprintf('Selected source %d, with TE(%d->%d | %s)=%.5f, p-value=%.5f (conditioning on %d parents)\n', ...
strongestSource, strongestSource, targetIndex, strjoin(string(parentSet)), maxTE, pValue, length(parentSet));
end
candidates(maxIndex) = []; % Remove this source from the candidates
parentSet = [parentSet, strongestSource];
results = [results, maxTE];
pValues = [pValues, pValue];
else
% Source was not significant, so we quit
if (parameters.verbose)
fprintf('-- Max TE source %d was not significant (TE(%d->%d | %s)=%.5f, p-value=%.6f (threshold %.6f)), quitting\n', ...
strongestSource, strongestSource, targetIndex, strjoin(string(parentSet)), maxTE, pValue, 1-threshold);
end
break;
end
toc
end
if (parameters.verbose)
fprintf('\nFinal selected parents: %s -> %d\n', strjoin(string(parentSet)), targetIndex);
end
end
% Returns the first time the ACF dips below 1/e for the series x,
% or if there are multiple series for x we take the mean across all of them
function acfDecayTime = computeAcfDecayTime(x, parameters)
numTrials = size(x,2);
acfDecayTimes = zeros(1,numTrials);
for trial = 1 : numTrials
[acfValues, ~] = autocorr(x(:, trial), 'NumLags', parameters.maxDynCorrExclLags);
acfDecayTimes(trial) = parameters.maxDynCorrExclLags; % Default is max value
for t = 1 : parameters.maxDynCorrExclLags
if (acfValues(t) < exp(-1))
acfDecayTimes(trial) = t;
break;
end
end
end
acfDecayTime = round(mean(acfDecayTimes));
end

View File

@ -0,0 +1,740 @@
;; Adapted by J.T. Lizier from the original CC BY NC SA 3.0 licensed Flocking model from NetLogo
;; and released under the same license.
;; See license info on the Info tab (and below if viewing text file)
globals [
headings-file
positionsx-file
positionsy-file
sorted-agents
]
turtles-own [
flockmates ;; agentset of nearby turtles
nearest-neighbor ;; closest one of our flockmates
]
to setup
clear-all
create-turtles population
[ set color yellow - 2 + random 7 ;; random shades look nice
set size 1.5 ;; easier to see
setxy random-xcor random-ycor
set flockmates no-turtles ]
reset-ticks
;; Set up for file output of data:
set headings-file "headings.txt"
set positionsx-file "positionsx.txt"
set positionsy-file "positionsy.txt"
if file-exists? headings-file [
file-delete headings-file ;; clear file
]
if file-exists? positionsx-file [
file-delete positionsx-file ;; clear file
]
if file-exists? positionsy-file [
file-delete positionsy-file ;; clear file
]
set sorted-agents sort turtles
end
to go
ask turtles [ flock ]
;; the following line is used to make the turtles
;; animate more smoothly.
repeat 5 [ ask turtles [ fd 0.2 ] display ]
;; for greater efficiency, at the expense of smooth
;; animation, substitute the following line instead:
;; ask turtles [ fd 1 ]
capture-data ;; write the current position+heading data of turtles to file
tick
end
to flock ;; turtle procedure
find-flockmates
if any? flockmates
[ find-nearest-neighbor
ifelse distance nearest-neighbor < minimum-separation
[ separate ]
[ align
cohere ] ]
end
to find-flockmates ;; turtle procedure
set flockmates other turtles in-radius vision
end
to find-nearest-neighbor ;; turtle procedure
set nearest-neighbor min-one-of flockmates [distance myself]
end
;;; SEPARATE
to separate ;; turtle procedure
turn-away ([heading] of nearest-neighbor) max-separate-turn
end
;;; ALIGN
to align ;; turtle procedure
turn-towards average-flockmate-heading max-align-turn
end
to-report average-flockmate-heading ;; turtle procedure
;; We can't just average the heading variables here.
;; For example, the average of 1 and 359 should be 0,
;; not 180. So we have to use trigonometry.
let x-component sum [dx] of flockmates
let y-component sum [dy] of flockmates
ifelse x-component = 0 and y-component = 0
[ report heading ]
[ report atan x-component y-component ]
end
;;; COHERE
to cohere ;; turtle procedure
turn-towards average-heading-towards-flockmates max-cohere-turn
end
to-report average-heading-towards-flockmates ;; turtle procedure
;; "towards myself" gives us the heading from the other turtle
;; to me, but we want the heading from me to the other turtle,
;; so we add 180
let x-component mean [sin (towards myself + 180)] of flockmates
let y-component mean [cos (towards myself + 180)] of flockmates
ifelse x-component = 0 and y-component = 0
[ report heading ]
[ report atan x-component y-component ]
end
;;; HELPER PROCEDURES
to turn-towards [new-heading max-turn] ;; turtle procedure
turn-at-most (subtract-headings new-heading heading) max-turn
end
to turn-away [new-heading max-turn] ;; turtle procedure
turn-at-most (subtract-headings heading new-heading) max-turn
end
;; turn right by "turn" degrees (or left if "turn" is negative),
;; but never turn more than "max-turn" degrees
to turn-at-most [turn max-turn] ;; turtle procedure
ifelse abs turn > max-turn
[ ifelse turn > 0
[ rt max-turn ]
[ lt max-turn ] ]
[ rt turn ]
end
to capture-data
;; To do a one-off:
;; file-open "headings.txt"
;; ;; Does not select turtles in order:
;; ask turtles [ file-print heading ]
;; file-close
if ticks > 4000
[ stop ]
;; Write the current headings
file-open headings-file ;; Opening file for writing
foreach sorted-agents [
[the-turtle] ->
ask the-turtle [
file-write heading
]
]
file-print " " ;; Terminate the line
file-close
;; Write the x positions
file-open positionsx-file ;; Opening file for writing
foreach sorted-agents [
[the-turtle] ->
ask the-turtle [
file-write xcor
]
]
file-print " " ;; Terminate the line
file-close
;; Write the y positions
file-open positionsy-file ;; Opening file for writing
foreach sorted-agents [
[the-turtle] ->
ask the-turtle [
file-write ycor
]
]
file-print " " ;; Terminate the line
file-close
end
; Copyright 1998 Uri Wilensky.
; See Info tab for full copyright and license.
@#$#@#$#@
GRAPHICS-WINDOW
250
10
755
516
-1
-1
7.0
1
10
1
1
1
0
1
1
1
-35
35
-35
35
1
1
1
ticks
30.0
BUTTON
39
93
116
126
NIL
setup
NIL
1
T
OBSERVER
NIL
NIL
NIL
NIL
1
BUTTON
122
93
203
126
NIL
go
T
1
T
OBSERVER
NIL
NIL
NIL
NIL
0
SLIDER
9
51
232
84
population
population
1.0
1000.0
300.0
1.0
1
NIL
HORIZONTAL
SLIDER
4
217
237
250
max-align-turn
max-align-turn
0.0
20.0
5.0
0.25
1
degrees
HORIZONTAL
SLIDER
4
251
237
284
max-cohere-turn
max-cohere-turn
0.0
20.0
3.0
0.25
1
degrees
HORIZONTAL
SLIDER
4
285
237
318
max-separate-turn
max-separate-turn
0.0
20.0
1.5
0.25
1
degrees
HORIZONTAL
SLIDER
9
135
232
168
vision
vision
0.0
10.0
3.0
0.5
1
patches
HORIZONTAL
SLIDER
9
169
232
202
minimum-separation
minimum-separation
0.0
5.0
1.0
0.25
1
patches
HORIZONTAL
@#$#@#$#@
## WHAT IS IT?
This model is an attempt to mimic the flocking of birds. (The resulting motion also resembles schools of fish.) The flocks that appear in this model are not created or led in any way by special leader birds. Rather, each bird is following exactly the same set of rules, from which flocks emerge.
## HOW IT WORKS
The birds follow three rules: "alignment", "separation", and "cohesion".
"Alignment" means that a bird tends to turn so that it is moving in the same direction that nearby birds are moving.
"Separation" means that a bird will turn to avoid another bird which gets too close.
"Cohesion" means that a bird will move towards other nearby birds (unless another bird is too close).
When two birds are too close, the "separation" rule overrides the other two, which are deactivated until the minimum separation is achieved.
The three rules affect only the bird's heading. Each bird always moves forward at the same constant speed.
## HOW TO USE IT
First, determine the number of birds you want in the simulation and set the POPULATION slider to that value. Press SETUP to create the birds, and press GO to have them start flying around.
The default settings for the sliders will produce reasonably good flocking behavior. However, you can play with them to get variations:
Three TURN-ANGLE sliders control the maximum angle a bird can turn as a result of each rule.
VISION is the distance that each bird can see 360 degrees around it.
## THINGS TO NOTICE
Central to the model is the observation that flocks form without a leader.
There are no random numbers used in this model, except to position the birds initially. The fluid, lifelike behavior of the birds is produced entirely by deterministic rules.
Also, notice that each flock is dynamic. A flock, once together, is not guaranteed to keep all of its members. Why do you think this is?
After running the model for a while, all of the birds have approximately the same heading. Why?
Sometimes a bird breaks away from its flock. How does this happen? You may need to slow down the model or run it step by step in order to observe this phenomenon.
## THINGS TO TRY
Play with the sliders to see if you can get tighter flocks, looser flocks, fewer flocks, more flocks, more or less splitting and joining of flocks, more or less rearranging of birds within flocks, etc.
You can turn off a rule entirely by setting that rule's angle slider to zero. Is one rule by itself enough to produce at least some flocking? What about two rules? What's missing from the resulting behavior when you leave out each rule?
Will running the model for a long time produce a static flock? Or will the birds never settle down to an unchanging formation? Remember, there are no random numbers used in this model.
## EXTENDING THE MODEL
Currently the birds can "see" all around them. What happens if birds can only see in front of them? The `in-cone` primitive can be used for this.
Is there some way to get V-shaped flocks, like migrating geese?
What happens if you put walls around the edges of the world that the birds can't fly into?
Can you get the birds to fly around obstacles in the middle of the world?
What would happen if you gave the birds different velocities? For example, you could make birds that are not near other birds fly faster to catch up to the flock. Or, you could simulate the diminished air resistance that birds experience when flying together by making them fly faster when in a group.
Are there other interesting ways you can make the birds different from each other? There could be random variation in the population, or you could have distinct "species" of bird.
## NETLOGO FEATURES
Notice the need for the `subtract-headings` primitive and special procedure for averaging groups of headings. Just subtracting the numbers, or averaging the numbers, doesn't give you the results you'd expect, because of the discontinuity where headings wrap back to 0 once they reach 360.
## RELATED MODELS
* Moths
* Flocking Vee Formation
* Flocking - Alternative Visualizations
## CREDITS AND REFERENCES
(Note: This is an adaptation by J.T. Lizier of the original Flocking model distributed in the NetLogo Models Library, under CC BY NC SA license (see below))
This model is inspired by the Boids simulation invented by Craig Reynolds. The algorithm we use here is roughly similar to the original Boids algorithm, but it is not the same. The exact details of the algorithm tend not to matter very much -- as long as you have alignment, separation, and cohesion, you will usually get flocking behavior resembling that produced by Reynolds' original model. Information on Boids is available at http://www.red3d.com/cwr/boids/.
## HOW TO CITE
If you mention this model or the NetLogo software in a publication, we ask that you include the citations below.
For the model itself:
* Wilensky, U. (1998). NetLogo Flocking model. http://ccl.northwestern.edu/netlogo/models/Flocking. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
Please cite the NetLogo software as:
* Wilensky, U. (1999). NetLogo. http://ccl.northwestern.edu/netlogo/. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
## COPYRIGHT AND LICENSE
Copyright 1998 Uri Wilensky.
![CC BY-NC-SA 3.0](http://ccl.northwestern.edu/images/creativecommons/byncsa.png)
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License. To view a copy of this license, visit https://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
Commercial licenses are also available. To inquire about commercial licenses, please contact Uri Wilensky at uri@northwestern.edu.
This model was created as part of the project: CONNECTED MATHEMATICS: MAKING SENSE OF COMPLEX PHENOMENA THROUGH BUILDING OBJECT-BASED PARALLEL MODELS (OBPML). The project gratefully acknowledges the support of the National Science Foundation (Applications of Advanced Technologies Program) -- grant numbers RED #9552950 and REC #9632612.
This model was converted to NetLogo as part of the projects: PARTICIPATORY SIMULATIONS: NETWORK-BASED DESIGN FOR SYSTEMS LEARNING IN CLASSROOMS and/or INTEGRATED SIMULATION AND MODELING ENVIRONMENT. The project gratefully acknowledges the support of the National Science Foundation (REPP & ROLE programs) -- grant numbers REC #9814682 and REC-0126227. Converted from StarLogoT to NetLogo, 2002.
<!-- 1998 2002 -->
@#$#@#$#@
default
true
0
Polygon -7500403 true true 150 5 40 250 150 205 260 250
airplane
true
0
Polygon -7500403 true true 150 0 135 15 120 60 120 105 15 165 15 195 120 180 135 240 105 270 120 285 150 270 180 285 210 270 165 240 180 180 285 195 285 165 180 105 180 60 165 15
arrow
true
0
Polygon -7500403 true true 150 0 0 150 105 150 105 293 195 293 195 150 300 150
box
false
0
Polygon -7500403 true true 150 285 285 225 285 75 150 135
Polygon -7500403 true true 150 135 15 75 150 15 285 75
Polygon -7500403 true true 15 75 15 225 150 285 150 135
Line -16777216 false 150 285 150 135
Line -16777216 false 150 135 15 75
Line -16777216 false 150 135 285 75
bug
true
0
Circle -7500403 true true 96 182 108
Circle -7500403 true true 110 127 80
Circle -7500403 true true 110 75 80
Line -7500403 true 150 100 80 30
Line -7500403 true 150 100 220 30
butterfly
true
0
Polygon -7500403 true true 150 165 209 199 225 225 225 255 195 270 165 255 150 240
Polygon -7500403 true true 150 165 89 198 75 225 75 255 105 270 135 255 150 240
Polygon -7500403 true true 139 148 100 105 55 90 25 90 10 105 10 135 25 180 40 195 85 194 139 163
Polygon -7500403 true true 162 150 200 105 245 90 275 90 290 105 290 135 275 180 260 195 215 195 162 165
Polygon -16777216 true false 150 255 135 225 120 150 135 120 150 105 165 120 180 150 165 225
Circle -16777216 true false 135 90 30
Line -16777216 false 150 105 195 60
Line -16777216 false 150 105 105 60
car
false
0
Polygon -7500403 true true 300 180 279 164 261 144 240 135 226 132 213 106 203 84 185 63 159 50 135 50 75 60 0 150 0 165 0 225 300 225 300 180
Circle -16777216 true false 180 180 90
Circle -16777216 true false 30 180 90
Polygon -16777216 true false 162 80 132 78 134 135 209 135 194 105 189 96 180 89
Circle -7500403 true true 47 195 58
Circle -7500403 true true 195 195 58
circle
false
0
Circle -7500403 true true 0 0 300
circle 2
false
0
Circle -7500403 true true 0 0 300
Circle -16777216 true false 30 30 240
cow
false
0
Polygon -7500403 true true 200 193 197 249 179 249 177 196 166 187 140 189 93 191 78 179 72 211 49 209 48 181 37 149 25 120 25 89 45 72 103 84 179 75 198 76 252 64 272 81 293 103 285 121 255 121 242 118 224 167
Polygon -7500403 true true 73 210 86 251 62 249 48 208
Polygon -7500403 true true 25 114 16 195 9 204 23 213 25 200 39 123
cylinder
false
0
Circle -7500403 true true 0 0 300
dot
false
0
Circle -7500403 true true 90 90 120
face happy
false
0
Circle -7500403 true true 8 8 285
Circle -16777216 true false 60 75 60
Circle -16777216 true false 180 75 60
Polygon -16777216 true false 150 255 90 239 62 213 47 191 67 179 90 203 109 218 150 225 192 218 210 203 227 181 251 194 236 217 212 240
face neutral
false
0
Circle -7500403 true true 8 7 285
Circle -16777216 true false 60 75 60
Circle -16777216 true false 180 75 60
Rectangle -16777216 true false 60 195 240 225
face sad
false
0
Circle -7500403 true true 8 8 285
Circle -16777216 true false 60 75 60
Circle -16777216 true false 180 75 60
Polygon -16777216 true false 150 168 90 184 62 210 47 232 67 244 90 220 109 205 150 198 192 205 210 220 227 242 251 229 236 206 212 183
fish
false
0
Polygon -1 true false 44 131 21 87 15 86 0 120 15 150 0 180 13 214 20 212 45 166
Polygon -1 true false 135 195 119 235 95 218 76 210 46 204 60 165
Polygon -1 true false 75 45 83 77 71 103 86 114 166 78 135 60
Polygon -7500403 true true 30 136 151 77 226 81 280 119 292 146 292 160 287 170 270 195 195 210 151 212 30 166
Circle -16777216 true false 215 106 30
flag
false
0
Rectangle -7500403 true true 60 15 75 300
Polygon -7500403 true true 90 150 270 90 90 30
Line -7500403 true 75 135 90 135
Line -7500403 true 75 45 90 45
flower
false
0
Polygon -10899396 true false 135 120 165 165 180 210 180 240 150 300 165 300 195 240 195 195 165 135
Circle -7500403 true true 85 132 38
Circle -7500403 true true 130 147 38
Circle -7500403 true true 192 85 38
Circle -7500403 true true 85 40 38
Circle -7500403 true true 177 40 38
Circle -7500403 true true 177 132 38
Circle -7500403 true true 70 85 38
Circle -7500403 true true 130 25 38
Circle -7500403 true true 96 51 108
Circle -16777216 true false 113 68 74
Polygon -10899396 true false 189 233 219 188 249 173 279 188 234 218
Polygon -10899396 true false 180 255 150 210 105 210 75 240 135 240
house
false
0
Rectangle -7500403 true true 45 120 255 285
Rectangle -16777216 true false 120 210 180 285
Polygon -7500403 true true 15 120 150 15 285 120
Line -16777216 false 30 120 270 120
leaf
false
0
Polygon -7500403 true true 150 210 135 195 120 210 60 210 30 195 60 180 60 165 15 135 30 120 15 105 40 104 45 90 60 90 90 105 105 120 120 120 105 60 120 60 135 30 150 15 165 30 180 60 195 60 180 120 195 120 210 105 240 90 255 90 263 104 285 105 270 120 285 135 240 165 240 180 270 195 240 210 180 210 165 195
Polygon -7500403 true true 135 195 135 240 120 255 105 255 105 285 135 285 165 240 165 195
line
true
0
Line -7500403 true 150 0 150 300
line half
true
0
Line -7500403 true 150 0 150 150
pentagon
false
0
Polygon -7500403 true true 150 15 15 120 60 285 240 285 285 120
person
false
0
Circle -7500403 true true 110 5 80
Polygon -7500403 true true 105 90 120 195 90 285 105 300 135 300 150 225 165 300 195 300 210 285 180 195 195 90
Rectangle -7500403 true true 127 79 172 94
Polygon -7500403 true true 195 90 240 150 225 180 165 105
Polygon -7500403 true true 105 90 60 150 75 180 135 105
plant
false
0
Rectangle -7500403 true true 135 90 165 300
Polygon -7500403 true true 135 255 90 210 45 195 75 255 135 285
Polygon -7500403 true true 165 255 210 210 255 195 225 255 165 285
Polygon -7500403 true true 135 180 90 135 45 120 75 180 135 210
Polygon -7500403 true true 165 180 165 210 225 180 255 120 210 135
Polygon -7500403 true true 135 105 90 60 45 45 75 105 135 135
Polygon -7500403 true true 165 105 165 135 225 105 255 45 210 60
Polygon -7500403 true true 135 90 120 45 150 15 180 45 165 90
square
false
0
Rectangle -7500403 true true 30 30 270 270
square 2
false
0
Rectangle -7500403 true true 30 30 270 270
Rectangle -16777216 true false 60 60 240 240
star
false
0
Polygon -7500403 true true 151 1 185 108 298 108 207 175 242 282 151 216 59 282 94 175 3 108 116 108
target
false
0
Circle -7500403 true true 0 0 300
Circle -16777216 true false 30 30 240
Circle -7500403 true true 60 60 180
Circle -16777216 true false 90 90 120
Circle -7500403 true true 120 120 60
tree
false
0
Circle -7500403 true true 118 3 94
Rectangle -6459832 true false 120 195 180 300
Circle -7500403 true true 65 21 108
Circle -7500403 true true 116 41 127
Circle -7500403 true true 45 90 120
Circle -7500403 true true 104 74 152
triangle
false
0
Polygon -7500403 true true 150 30 15 255 285 255
triangle 2
false
0
Polygon -7500403 true true 150 30 15 255 285 255
Polygon -16777216 true false 151 99 225 223 75 224
truck
false
0
Rectangle -7500403 true true 4 45 195 187
Polygon -7500403 true true 296 193 296 150 259 134 244 104 208 104 207 194
Rectangle -1 true false 195 60 195 105
Polygon -16777216 true false 238 112 252 141 219 141 218 112
Circle -16777216 true false 234 174 42
Rectangle -7500403 true true 181 185 214 194
Circle -16777216 true false 144 174 42
Circle -16777216 true false 24 174 42
Circle -7500403 false true 24 174 42
Circle -7500403 false true 144 174 42
Circle -7500403 false true 234 174 42
turtle
true
0
Polygon -10899396 true false 215 204 240 233 246 254 228 266 215 252 193 210
Polygon -10899396 true false 195 90 225 75 245 75 260 89 269 108 261 124 240 105 225 105 210 105
Polygon -10899396 true false 105 90 75 75 55 75 40 89 31 108 39 124 60 105 75 105 90 105
Polygon -10899396 true false 132 85 134 64 107 51 108 17 150 2 192 18 192 52 169 65 172 87
Polygon -10899396 true false 85 204 60 233 54 254 72 266 85 252 107 210
Polygon -7500403 true true 119 75 179 75 209 101 224 135 220 225 175 261 128 261 81 224 74 135 88 99
wheel
false
0
Circle -7500403 true true 3 3 294
Circle -16777216 true false 30 30 240
Line -7500403 true 150 285 150 15
Line -7500403 true 15 150 285 150
Circle -7500403 true true 120 120 60
Line -7500403 true 216 40 79 269
Line -7500403 true 40 84 269 221
Line -7500403 true 40 216 269 79
Line -7500403 true 84 40 221 269
x
false
0
Polygon -7500403 true true 270 75 225 30 30 225 75 270
Polygon -7500403 true true 30 75 75 30 270 225 225 270
@#$#@#$#@
NetLogo 6.0
@#$#@#$#@
set population 200
setup
repeat 200 [ go ]
@#$#@#$#@
@#$#@#$#@
@#$#@#$#@
@#$#@#$#@
default
0.0
-0.2 0 0.0 1.0
0.0 1 1.0 0.0
0.2 0 0.0 1.0
link direction
true
0
Line -7500403 true 150 150 90 180
Line -7500403 true 150 150 210 180
@#$#@#$#@
0
@#$#@#$#@

View File

@ -0,0 +1,810 @@
;; Adapted by J.T. Lizier and S. Sekhar from the original CC BY NC SA 3.0 licensed Flocking model from NetLogo
;; and released under the same license.
;; See license info on the Info tab (and below if viewing text file)
globals [
headings-file
positionsx-file
positionsy-file
sorted-agents
]
turtles-own [
flockmates ;; agentset of nearby turtles
nearest-neighbor ;; closest one of our flockmates
speed
]
to setup
clear-all
create-turtles population
[ set color yellow - 2 + random 7 ;; random shades look nice
set size 1.5 ;; easier to see
setxy random-xcor random-ycor
set flockmates no-turtles
set speed ((random-float 0.5) + 0.25)
]
reset-ticks
;; Set up for file output of data:
set headings-file "headings.txt"
set positionsx-file "positionsx.txt"
set positionsy-file "positionsy.txt"
if file-exists? headings-file [
file-delete headings-file ;; clear file
]
if file-exists? positionsx-file [
file-delete positionsx-file ;; clear file
]
if file-exists? positionsy-file [
file-delete positionsy-file ;; clear file
]
set sorted-agents sort turtles
end
to go
ask turtles [
fd speed
flock ]
if ticks > 0 [ ;; You can take data after a larger number of ticks to remove a transient
capture-data ];; write the current position+heading data of turtles to file
tick
end
to flock ;; turtle procedure
find-flockmates
if any? flockmates
[ find-nearest-neighbor
ifelse distance nearest-neighbor < minimum-separation
[ separate ]
[ align
cohere
speedmatch
] ]
end
to find-flockmates ;; turtle procedure
set flockmates other turtles in-radius vision
end
to find-nearest-neighbor ;; turtle procedure
set nearest-neighbor min-one-of flockmates [distance myself]
end
;;; SEPARATE
to separate ;; turtle procedure
turn-away ([heading] of nearest-neighbor) max-separate-turn
end
;;;SPEEDMATCH
to speedmatch
let speed-change (abs(speed - average-flockmate-speed) * 0.80 )
( ifelse average-flockmate-speed > speed
[ set speed (speed + speed-change) ]
[ set speed (speed - speed-change) ] )
set speed (speed + speed-change * ((random-float 0.2) - 0.1))
end
to-report average-flockmate-speed
let speed-component mean [speed] of flockmates
report speed-component
end
;;; ALIGN
to align ;; turtle procedure
turn-towards average-flockmate-heading max-align-turn
end
to-report average-flockmate-heading ;; turtle procedure
;; We can't just average the heading variables here.
;; For example, the average of 1 and 359 should be 0,
;; not 180. So we have to use trigonometry.
let x-component sum [dx] of flockmates
let y-component sum [dy] of flockmates
ifelse x-component = 0 and y-component = 0
[ report heading ]
[ report atan x-component y-component ]
end
;;; COHERE
to cohere ;; turtle procedure
turn-towards average-heading-towards-flockmates max-cohere-turn
end
to-report average-heading-towards-flockmates ;; turtle procedure
;; "towards myself" gives us the heading from the other turtle
;; to me, but we want the heading from me to the other turtle,
;; so we add 180
let x-component mean [sin (towards myself + 180)] of flockmates
let y-component mean [cos (towards myself + 180)] of flockmates
ifelse x-component = 0 and y-component = 0
[ report heading ]
[ report atan x-component y-component ]
end
;;; HELPER PROCEDURES
to turn-towards [new-heading max-turn] ;; turtle procedure
turn-at-most (subtract-headings new-heading heading) max-turn
end
to turn-away [new-heading max-turn] ;; turtle procedure
turn-at-most (subtract-headings heading new-heading) max-turn
end
;; turn right by "turn" degrees (or left if "turn" is negative),
;; but never turn more than "max-turn" degrees
to turn-at-most [turn max-turn] ;; turtle procedure
ifelse abs turn > max-turn
[ ifelse turn > 0
[ rt max-turn ]
[ lt max-turn ] ]
[ rt turn ]
end
to capture-data
;; To do a one-off:
;; file-open "headings.txt"
;; ;; Does not select turtles in order:
;; ask turtles [ file-print heading ]
;; file-close
if ticks > 4000
[ stop ]
;; Write the current headings
file-open headings-file ;; Opening file for writing
foreach sorted-agents [
[the-turtle] ->
ask the-turtle [
file-write heading
]
]
file-print " " ;; Terminate the line
file-close
;; Write the x positions
file-open positionsx-file ;; Opening file for writing
foreach sorted-agents [
[the-turtle] ->
ask the-turtle [
file-write xcor
]
]
file-print " " ;; Terminate the line
file-close
;; Write the y positions
file-open positionsy-file ;; Opening file for writing
foreach sorted-agents [
[the-turtle] ->
ask the-turtle [
file-write ycor
]
]
file-print " " ;; Terminate the line
file-close
end
; Copyright 1998 Uri Wilensky.
; See Info tab for full copyright and license.
@#$#@#$#@
GRAPHICS-WINDOW
250
10
755
516
-1
-1
7.0
1
10
1
1
1
0
1
1
1
-35
35
-35
35
1
1
1
ticks
30.0
BUTTON
39
93
116
126
NIL
setup
NIL
1
T
OBSERVER
NIL
NIL
NIL
NIL
1
BUTTON
122
93
203
126
NIL
go
T
1
T
OBSERVER
NIL
NIL
NIL
NIL
0
SLIDER
9
51
232
84
population
population
1.0
1000.0
300.0
1.0
1
NIL
HORIZONTAL
SLIDER
4
217
237
250
max-align-turn
max-align-turn
0.0
20.0
5.0
0.25
1
degrees
HORIZONTAL
SLIDER
4
251
237
284
max-cohere-turn
max-cohere-turn
0.0
20.0
3.0
0.25
1
degrees
HORIZONTAL
SLIDER
4
285
237
318
max-separate-turn
max-separate-turn
0.0
20.0
1.5
0.25
1
degrees
HORIZONTAL
SLIDER
9
135
232
168
vision
vision
0.0
10.0
3.0
0.5
1
patches
HORIZONTAL
SLIDER
9
169
232
202
minimum-separation
minimum-separation
0.0
5.0
1.0
0.25
1
patches
HORIZONTAL
PLOT
757
42
1051
447
plot 1
Speed
Turtles
0.2
0.8
0.0
100.0
true
false
"\n\nset-histogram-num-bars 20" ""
PENS
"default" 1.0 1 -16777216 true "" "histogram [speed] of turtles\n"
MONITOR
30
434
173
479
NIL
mean [speed] of turtles
10
1
11
MONITOR
95
376
216
421
NIL
[speed] of turtle 25
10
1
11
MONITOR
23
329
151
374
NIL
[speed] of turtle 213
10
1
11
@#$#@#$#@
## WHAT IS IT?
This model is an attempt to mimic the flocking of birds. (The resulting motion also resembles schools of fish.) The flocks that appear in this model are not created or led in any way by special leader birds. Rather, each bird is following exactly the same set of rules, from which flocks emerge.
## HOW IT WORKS
The birds follow three rules: "alignment", "separation", and "cohesion".
"Alignment" means that a bird tends to turn so that it is moving in the same direction that nearby birds are moving.
"Separation" means that a bird will turn to avoid another bird which gets too close.
"Cohesion" means that a bird will move towards other nearby birds (unless another bird is too close).
When two birds are too close, the "separation" rule overrides the other two, which are deactivated until the minimum separation is achieved.
The three rules affect only the bird's heading. Each bird always moves forward at the same constant speed.
## HOW TO USE IT
First, determine the number of birds you want in the simulation and set the POPULATION slider to that value. Press SETUP to create the birds, and press GO to have them start flying around.
The default settings for the sliders will produce reasonably good flocking behavior. However, you can play with them to get variations:
Three TURN-ANGLE sliders control the maximum angle a bird can turn as a result of each rule.
VISION is the distance that each bird can see 360 degrees around it.
## THINGS TO NOTICE
Central to the model is the observation that flocks form without a leader.
There are no random numbers used in this model, except to position the birds initially. The fluid, lifelike behavior of the birds is produced entirely by deterministic rules.
Also, notice that each flock is dynamic. A flock, once together, is not guaranteed to keep all of its members. Why do you think this is?
After running the model for a while, all of the birds have approximately the same heading. Why?
Sometimes a bird breaks away from its flock. How does this happen? You may need to slow down the model or run it step by step in order to observe this phenomenon.
## THINGS TO TRY
Play with the sliders to see if you can get tighter flocks, looser flocks, fewer flocks, more flocks, more or less splitting and joining of flocks, more or less rearranging of birds within flocks, etc.
You can turn off a rule entirely by setting that rule's angle slider to zero. Is one rule by itself enough to produce at least some flocking? What about two rules? What's missing from the resulting behavior when you leave out each rule?
Will running the model for a long time produce a static flock? Or will the birds never settle down to an unchanging formation? Remember, there are no random numbers used in this model.
## EXTENDING THE MODEL
Currently the birds can "see" all around them. What happens if birds can only see in front of them? The `in-cone` primitive can be used for this.
Is there some way to get V-shaped flocks, like migrating geese?
What happens if you put walls around the edges of the world that the birds can't fly into?
Can you get the birds to fly around obstacles in the middle of the world?
What would happen if you gave the birds different velocities? For example, you could make birds that are not near other birds fly faster to catch up to the flock. Or, you could simulate the diminished air resistance that birds experience when flying together by making them fly faster when in a group.
Are there other interesting ways you can make the birds different from each other? There could be random variation in the population, or you could have distinct "species" of bird.
## NETLOGO FEATURES
Notice the need for the `subtract-headings` primitive and special procedure for averaging groups of headings. Just subtracting the numbers, or averaging the numbers, doesn't give you the results you'd expect, because of the discontinuity where headings wrap back to 0 once they reach 360.
## RELATED MODELS
* Moths
* Flocking Vee Formation
* Flocking - Alternative Visualizations
## CREDITS AND REFERENCES
(Note: This is an adaptation by J.T. Lizier of the original Flocking model distributed in the NetLogo Models Library, under CC BY NC SA license (see below))
This model is inspired by the Boids simulation invented by Craig Reynolds. The algorithm we use here is roughly similar to the original Boids algorithm, but it is not the same. The exact details of the algorithm tend not to matter very much -- as long as you have alignment, separation, and cohesion, you will usually get flocking behavior resembling that produced by Reynolds' original model. Information on Boids is available at http://www.red3d.com/cwr/boids/.
## HOW TO CITE
If you mention this model or the NetLogo software in a publication, we ask that you include the citations below.
For the model itself:
* Wilensky, U. (1998). NetLogo Flocking model. http://ccl.northwestern.edu/netlogo/models/Flocking. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
Please cite the NetLogo software as:
* Wilensky, U. (1999). NetLogo. http://ccl.northwestern.edu/netlogo/. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
## COPYRIGHT AND LICENSE
Copyright 1998 Uri Wilensky.
![CC BY-NC-SA 3.0](http://ccl.northwestern.edu/images/creativecommons/byncsa.png)
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License. To view a copy of this license, visit https://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
Commercial licenses are also available. To inquire about commercial licenses, please contact Uri Wilensky at uri@northwestern.edu.
This model was created as part of the project: CONNECTED MATHEMATICS: MAKING SENSE OF COMPLEX PHENOMENA THROUGH BUILDING OBJECT-BASED PARALLEL MODELS (OBPML). The project gratefully acknowledges the support of the National Science Foundation (Applications of Advanced Technologies Program) -- grant numbers RED #9552950 and REC #9632612.
This model was converted to NetLogo as part of the projects: PARTICIPATORY SIMULATIONS: NETWORK-BASED DESIGN FOR SYSTEMS LEARNING IN CLASSROOMS and/or INTEGRATED SIMULATION AND MODELING ENVIRONMENT. The project gratefully acknowledges the support of the National Science Foundation (REPP & ROLE programs) -- grant numbers REC #9814682 and REC-0126227. Converted from StarLogoT to NetLogo, 2002.
<!-- 1998 2002 -->
@#$#@#$#@
default
true
0
Polygon -7500403 true true 150 5 40 250 150 205 260 250
airplane
true
0
Polygon -7500403 true true 150 0 135 15 120 60 120 105 15 165 15 195 120 180 135 240 105 270 120 285 150 270 180 285 210 270 165 240 180 180 285 195 285 165 180 105 180 60 165 15
arrow
true
0
Polygon -7500403 true true 150 0 0 150 105 150 105 293 195 293 195 150 300 150
box
false
0
Polygon -7500403 true true 150 285 285 225 285 75 150 135
Polygon -7500403 true true 150 135 15 75 150 15 285 75
Polygon -7500403 true true 15 75 15 225 150 285 150 135
Line -16777216 false 150 285 150 135
Line -16777216 false 150 135 15 75
Line -16777216 false 150 135 285 75
bug
true
0
Circle -7500403 true true 96 182 108
Circle -7500403 true true 110 127 80
Circle -7500403 true true 110 75 80
Line -7500403 true 150 100 80 30
Line -7500403 true 150 100 220 30
butterfly
true
0
Polygon -7500403 true true 150 165 209 199 225 225 225 255 195 270 165 255 150 240
Polygon -7500403 true true 150 165 89 198 75 225 75 255 105 270 135 255 150 240
Polygon -7500403 true true 139 148 100 105 55 90 25 90 10 105 10 135 25 180 40 195 85 194 139 163
Polygon -7500403 true true 162 150 200 105 245 90 275 90 290 105 290 135 275 180 260 195 215 195 162 165
Polygon -16777216 true false 150 255 135 225 120 150 135 120 150 105 165 120 180 150 165 225
Circle -16777216 true false 135 90 30
Line -16777216 false 150 105 195 60
Line -16777216 false 150 105 105 60
car
false
0
Polygon -7500403 true true 300 180 279 164 261 144 240 135 226 132 213 106 203 84 185 63 159 50 135 50 75 60 0 150 0 165 0 225 300 225 300 180
Circle -16777216 true false 180 180 90
Circle -16777216 true false 30 180 90
Polygon -16777216 true false 162 80 132 78 134 135 209 135 194 105 189 96 180 89
Circle -7500403 true true 47 195 58
Circle -7500403 true true 195 195 58
circle
false
0
Circle -7500403 true true 0 0 300
circle 2
false
0
Circle -7500403 true true 0 0 300
Circle -16777216 true false 30 30 240
cow
false
0
Polygon -7500403 true true 200 193 197 249 179 249 177 196 166 187 140 189 93 191 78 179 72 211 49 209 48 181 37 149 25 120 25 89 45 72 103 84 179 75 198 76 252 64 272 81 293 103 285 121 255 121 242 118 224 167
Polygon -7500403 true true 73 210 86 251 62 249 48 208
Polygon -7500403 true true 25 114 16 195 9 204 23 213 25 200 39 123
cylinder
false
0
Circle -7500403 true true 0 0 300
dot
false
0
Circle -7500403 true true 90 90 120
face happy
false
0
Circle -7500403 true true 8 8 285
Circle -16777216 true false 60 75 60
Circle -16777216 true false 180 75 60
Polygon -16777216 true false 150 255 90 239 62 213 47 191 67 179 90 203 109 218 150 225 192 218 210 203 227 181 251 194 236 217 212 240
face neutral
false
0
Circle -7500403 true true 8 7 285
Circle -16777216 true false 60 75 60
Circle -16777216 true false 180 75 60
Rectangle -16777216 true false 60 195 240 225
face sad
false
0
Circle -7500403 true true 8 8 285
Circle -16777216 true false 60 75 60
Circle -16777216 true false 180 75 60
Polygon -16777216 true false 150 168 90 184 62 210 47 232 67 244 90 220 109 205 150 198 192 205 210 220 227 242 251 229 236 206 212 183
fish
false
0
Polygon -1 true false 44 131 21 87 15 86 0 120 15 150 0 180 13 214 20 212 45 166
Polygon -1 true false 135 195 119 235 95 218 76 210 46 204 60 165
Polygon -1 true false 75 45 83 77 71 103 86 114 166 78 135 60
Polygon -7500403 true true 30 136 151 77 226 81 280 119 292 146 292 160 287 170 270 195 195 210 151 212 30 166
Circle -16777216 true false 215 106 30
flag
false
0
Rectangle -7500403 true true 60 15 75 300
Polygon -7500403 true true 90 150 270 90 90 30
Line -7500403 true 75 135 90 135
Line -7500403 true 75 45 90 45
flower
false
0
Polygon -10899396 true false 135 120 165 165 180 210 180 240 150 300 165 300 195 240 195 195 165 135
Circle -7500403 true true 85 132 38
Circle -7500403 true true 130 147 38
Circle -7500403 true true 192 85 38
Circle -7500403 true true 85 40 38
Circle -7500403 true true 177 40 38
Circle -7500403 true true 177 132 38
Circle -7500403 true true 70 85 38
Circle -7500403 true true 130 25 38
Circle -7500403 true true 96 51 108
Circle -16777216 true false 113 68 74
Polygon -10899396 true false 189 233 219 188 249 173 279 188 234 218
Polygon -10899396 true false 180 255 150 210 105 210 75 240 135 240
house
false
0
Rectangle -7500403 true true 45 120 255 285
Rectangle -16777216 true false 120 210 180 285
Polygon -7500403 true true 15 120 150 15 285 120
Line -16777216 false 30 120 270 120
leaf
false
0
Polygon -7500403 true true 150 210 135 195 120 210 60 210 30 195 60 180 60 165 15 135 30 120 15 105 40 104 45 90 60 90 90 105 105 120 120 120 105 60 120 60 135 30 150 15 165 30 180 60 195 60 180 120 195 120 210 105 240 90 255 90 263 104 285 105 270 120 285 135 240 165 240 180 270 195 240 210 180 210 165 195
Polygon -7500403 true true 135 195 135 240 120 255 105 255 105 285 135 285 165 240 165 195
line
true
0
Line -7500403 true 150 0 150 300
line half
true
0
Line -7500403 true 150 0 150 150
pentagon
false
0
Polygon -7500403 true true 150 15 15 120 60 285 240 285 285 120
person
false
0
Circle -7500403 true true 110 5 80
Polygon -7500403 true true 105 90 120 195 90 285 105 300 135 300 150 225 165 300 195 300 210 285 180 195 195 90
Rectangle -7500403 true true 127 79 172 94
Polygon -7500403 true true 195 90 240 150 225 180 165 105
Polygon -7500403 true true 105 90 60 150 75 180 135 105
plant
false
0
Rectangle -7500403 true true 135 90 165 300
Polygon -7500403 true true 135 255 90 210 45 195 75 255 135 285
Polygon -7500403 true true 165 255 210 210 255 195 225 255 165 285
Polygon -7500403 true true 135 180 90 135 45 120 75 180 135 210
Polygon -7500403 true true 165 180 165 210 225 180 255 120 210 135
Polygon -7500403 true true 135 105 90 60 45 45 75 105 135 135
Polygon -7500403 true true 165 105 165 135 225 105 255 45 210 60
Polygon -7500403 true true 135 90 120 45 150 15 180 45 165 90
square
false
0
Rectangle -7500403 true true 30 30 270 270
square 2
false
0
Rectangle -7500403 true true 30 30 270 270
Rectangle -16777216 true false 60 60 240 240
star
false
0
Polygon -7500403 true true 151 1 185 108 298 108 207 175 242 282 151 216 59 282 94 175 3 108 116 108
target
false
0
Circle -7500403 true true 0 0 300
Circle -16777216 true false 30 30 240
Circle -7500403 true true 60 60 180
Circle -16777216 true false 90 90 120
Circle -7500403 true true 120 120 60
tree
false
0
Circle -7500403 true true 118 3 94
Rectangle -6459832 true false 120 195 180 300
Circle -7500403 true true 65 21 108
Circle -7500403 true true 116 41 127
Circle -7500403 true true 45 90 120
Circle -7500403 true true 104 74 152
triangle
false
0
Polygon -7500403 true true 150 30 15 255 285 255
triangle 2
false
0
Polygon -7500403 true true 150 30 15 255 285 255
Polygon -16777216 true false 151 99 225 223 75 224
truck
false
0
Rectangle -7500403 true true 4 45 195 187
Polygon -7500403 true true 296 193 296 150 259 134 244 104 208 104 207 194
Rectangle -1 true false 195 60 195 105
Polygon -16777216 true false 238 112 252 141 219 141 218 112
Circle -16777216 true false 234 174 42
Rectangle -7500403 true true 181 185 214 194
Circle -16777216 true false 144 174 42
Circle -16777216 true false 24 174 42
Circle -7500403 false true 24 174 42
Circle -7500403 false true 144 174 42
Circle -7500403 false true 234 174 42
turtle
true
0
Polygon -10899396 true false 215 204 240 233 246 254 228 266 215 252 193 210
Polygon -10899396 true false 195 90 225 75 245 75 260 89 269 108 261 124 240 105 225 105 210 105
Polygon -10899396 true false 105 90 75 75 55 75 40 89 31 108 39 124 60 105 75 105 90 105
Polygon -10899396 true false 132 85 134 64 107 51 108 17 150 2 192 18 192 52 169 65 172 87
Polygon -10899396 true false 85 204 60 233 54 254 72 266 85 252 107 210
Polygon -7500403 true true 119 75 179 75 209 101 224 135 220 225 175 261 128 261 81 224 74 135 88 99
wheel
false
0
Circle -7500403 true true 3 3 294
Circle -16777216 true false 30 30 240
Line -7500403 true 150 285 150 15
Line -7500403 true 15 150 285 150
Circle -7500403 true true 120 120 60
Line -7500403 true 216 40 79 269
Line -7500403 true 40 84 269 221
Line -7500403 true 40 216 269 79
Line -7500403 true 84 40 221 269
x
false
0
Polygon -7500403 true true 270 75 225 30 30 225 75 270
Polygon -7500403 true true 30 75 75 30 270 225 225 270
@#$#@#$#@
NetLogo 6.0
@#$#@#$#@
set population 200
setup
repeat 200 [ go ]
@#$#@#$#@
@#$#@#$#@
@#$#@#$#@
@#$#@#$#@
default
0.0
-0.2 0 0.0 1.0
0.0 1 1.0 0.0
0.2 0 0.0 1.0
link direction
true
0
Line -7500403 true 150 150 90 180
Line -7500403 true 150 150 210 180
@#$#@#$#@
0
@#$#@#$#@

View File

@ -0,0 +1,113 @@
%
% This script loads properties for transfer entropy analysis of the data from
% the NetLogo Flocking model.
%
% Author: Joseph T. Lizier, Sooraj Sekhar, 2019
%
%%
%% Java Information Dynamics Toolkit (JIDT)
%% Copyright (C) 2019, 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/>.
%%
% This script loads the default properties for the transfer entropy processing:
clear('properties');
%%%%%%%%%
% FILENAMES
%%%%%%%%%
% Input data files:
% properties.files can be:
% a. a cell array of file names, e.g.: {'file1.xlsx', 'file2.xlsx'}
% b. a call to ls or ls with an argument, e.g. ls('*.xlsx')
% c. a space or tab separated character row vector of file names
% d. a character matrix of filenames (each filename on a separate row)
properties.files = 'positions%s.txt';
% Function to read in the data files:
% loadScript must point to a function .m file that accepts two arguments
% (the name of a file, and properties object) and returns [x,y,z] (z optional, only when 3D)
% data where each is an array, e.g. x(time, fishIndex) indexed first by time and second by fish index.
% Where an individual is not present at any given time step, set each x,y,z position
% to nan for these time steps. The subsequent scripts will then ignore these samples.
% Use the name of the .m file after an "@" character:
properties.loadScript = @loadseparatexy;
% Is the data returned by the loadScript 3D (true) or 2D (false)?
properties.data3d = false;
% Results file - will hold the parsed velocities / relative positions, plus the
% local transfer entropy results
properties.resultsFile = 'results.mat';
%%%%%%%%%
% PARAMETERS
%%%%%%%%%
% Distance within which to consider a pair for the info theoretic analysis (units are as per what is used in the data files)
properties.pairRange = 4; % These ones have a causal range of 3
%%%%%%%%%
% INFORMATION THEORETIC Parameters
% Only lag is used for computing lagged mutual information
% All lag, k and tau are used for transfer entropy
% k - embedding dimension of the past of the destination array.
% tau - embedding delay: time cycles separating each element in the past of the destination.
% lag - time delay between the source and target in cycles
% You can set kRange, tauRange and lagRange to ask that these are optimised by runAnalysis:
% properties.kRange = 1:10;
% properties.tauRange = 1:4;
% properties.lagRange = 1:10;
% You can also set k, tau and lag to values that generateObservations should use
% (although note that if this is called via runAnalysis then it will overwrite them):
properties.k = 1;
properties.tau = 1;
properties.lag = 1;
% Do we compute TE based on headings or speeds or both for the info calculations? (need at least one of these set to true)
properties.speedcalc = false;
properties.headingcalc = true;
% Additionally: Do we include the relative source position in the transfer entropy calculation (true), or
% only the relative source heading (false)
properties.includeSourcePositionInTransfer = false;
% Do we take relative source heading and position with respect to dest heading at that same
% time point (true, this is what we did for Crosato paper) or with respect
% to dest heading just previous to state update (false)?
% UPDATE THIS COMMENT TO MAKE MORE SENSE. Ash and Liss say false is more biologically realistic
properties.sourceWrtSameDestTime = true;
% JIDT location:
properties.jidtJarLocation = '../../../../infodynamics.jar';
% Which estimator to use.
% Valid values are 'gaussian' (linear) or 'kraskov' (non-linear)
% properties.estimator = 'gaussian';
properties.estimator = 'kraskov';
% Properties for JIDT estimators:
properties.jidt.kNNs = 4; % Number of nearest neighbours for Kraskov algorithm: just use 4 (default)
properties.jidt.autoDynamicCorrelationExclusion = true; % Exclude nearest neighbours from at least the same target transition from being included in counts for TE. This requires the Econometrics Toolbox in Matlab in order to call autocorr. Set to false if you don't have that to avoid this being called.
properties.aisNumSurrogates = 0; % Number of surrogate calculations to run for AIS (just to see the noise floor. 0 means skip)
properties.teNumSurrogates = 0; % Number of surrogate calculations to run for TE (just to see the noise floor. 0 means skip)
% Exit the analysis after calculating the AIS (i.e. don't compute TE)
properties.computeAISOnly = false;

Binary file not shown.

View File

@ -0,0 +1,73 @@
function ais = computeAIS(D, Dpast, properties)
% Computes active information storage from the pre-processed velocity data
%
% Author: Joseph T. Lizier, 2019
%
% Inputs:
% - D - target samples (may be multivariate as per generateObservations)
% - Dpast - target past samples (multivariate, and embedded up to k previous samples)
% - properties (required) - object with properties for the calculations,
% with sub-members as specificied in the loadProperties.m file. If not supplied
% the properties are loaded from loadProperties.m
%
% Outputs:
% - ais - active information storage value (MI between D and Dpast)
%%
%% Java Information Dynamics Toolkit (JIDT)
%% Copyright (C) 2019, Joseph T. Lizier et al.
%%
%% 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/>.
%%
% -- STEP 0 : create java object
% check out http://lizier.me/joseph/software/jidt/javadocs/v1.3/
% for the description of all classes and methods
javaaddpath(properties.jidtJarLocation); % add JIDT path
% Select correct MI class for this estimator type
if (strcmp('kraskov', properties.estimator))
MI_CLASS = 'infodynamics.measures.continuous.kraskov.MutualInfoCalculatorMultiVariateKraskov1';
else
MI_CLASS = 'infodynamics.measures.continuous.gaussian.MutualInfoCalculatorMultiVariateGaussian';
end
% Compute the information stored in the past of the target.
% Creates java object of the given class
AIScalculator = javaObject(MI_CLASS);
% -- STEP 1 : set properties
AIScalculator.setProperty('k', num2str(properties.jidt.kNNs));
AIScalculator.setProperty('BIAS_CORRECTION', 'true'); % Used for Gaussian only
% -- STEP 2 : initialise
% here the parameters are the dimensionality of the series
% in this case taken directly from the number of columns in each variable
AIScalculator.initialise(size(D,2), size(Dpast,2));
% -- STEP 3 : add in observations
AIScalculator.setObservations(D, Dpast);
% -- STEP 4 : compute the local AIS (will be bias-corrected now for either Gaussian or KSG)
ais = AIScalculator.computeAverageLocalOfObservations(); % global (average) value
fprintf('Mean AIS_%s (k=%d,tau=%d) = %.3f\n', properties.estimator, properties.k, properties.tau, ais);
if (properties.aisNumSurrogates > 0)
% Compute the (statistical significance via) null distribution empirically (e.g. with 100 permutations),
% and use this for empirical bias correction (otherwise we're relying on analytic)
aisMeasDist = AIScalculator.computeSignificance(properties.aisNumSurrogates);
fprintf('Null distribution: %.4f +/- %.4f std dev.; p(surrogate > measured)=%.3f from %d surrogates)\n', ...
aisMeasDist.getMeanOfDistribution(), aisMeasDist.getStdOfDistribution(), ...
aisMeasDist.pValue, properties.aisNumSurrogates);
ais = ais - aisMeasDist.getMeanOfDistribution();
fprintf('Bias corrected Mean AIS_%s (k=%d,tau=%d) = %.3f\n', properties.estimator, properties.k, properties.tau, ais);
end
end

View File

@ -0,0 +1,101 @@
function tranEntropy = computeTE(S, D, Dpast, properties)
% Computes transfer entropy from the pre-processed velocity data
%
% Author: Emanuele Crosato, Joseph T. Lizier, 2019
%
% Inputs:
% - S - source samples (may be multivariate as per generate3DObservations)
% - D - target samples (may be multivariate as per generate3DObservations)
% - Dpast - target past samples (multivariate, and embedded up to k previous samples)
% - properties (required) - object with properties for the calculations,
% with sub-members as specificied in the loadProperties.m file. If not supplied
% the properties are loaded from loadProperties.m
%
% Outputs:
% - te - transfer entropy value (conditional MI from S (maybe plus RelSourcePos) to D given Dpast). If not requested, then
% the te (and an array of local values) is saved to properties.resultsFile
%%
%% Java Information Dynamics Toolkit (JIDT)
%% Copyright (C) 2019, Joseph T. Lizier et al.
%%
%% 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/>.
%%
% -- STEP 0 : create java object
% check out http://lizier.me/joseph/software/jidt/javadocs/v1.3/
% for the description of all classes and methods
javaaddpath(properties.jidtJarLocation); % add JIDT path
% the following is the java class for conditional mutual information in JIDT
% transfer entropy is infact mutual information conditioning on the past
% of the destination
if (strcmp('kraskov', properties.estimator))
CMI_CLASS = 'infodynamics.measures.continuous.kraskov.ConditionalMutualInfoCalculatorMultiVariateKraskov1';
else
CMI_CLASS = 'infodynamics.measures.continuous.gaussian.ConditionalMutualInfoCalculatorMultiVariateGaussian';
end
TEcalculator = javaObject(CMI_CLASS); % creates a java object of the given class
% -- STEP 1 : set properties
TEcalculator.setProperty('k', num2str(properties.jidt.kNNs));
TEcalculator.setProperty('BIAS_CORRECTION', 'true'); % Used for Gaussian only
if (isfield(properties.jidt, 'dynamicCorrelationExclusion'))
% We'll ensure samples from the same target transition aren't included in nearest neighbour counts
% (it will exclude some others as well, but this only adds some small noise to the calculation)
TEcalculator.setProperty('DYN_CORR_EXCL', num2str(properties.jidt.dynamicCorrelationExclusion));
end
% -- STEP 2 : initialise
% here the parameters are the dimensionality of the series
% in this case taken directly from the number of columns in each variable
TEcalculator.initialise(size(S,2), size(D,2), size(Dpast,2));
% -- STEP 3 : add in observations
TEcalculator.setObservations(S, D, Dpast);
% -- STEP 4 : compute the local entropies
tranEntropy = TEcalculator.computeAverageLocalOfObservations(); % global (average) value
fprintf('Mean TE_%s (k=%d,tau=%d,lag=%d) = %.4f\n', ...
properties.estimator, properties.k, properties.tau, properties.lag, tranEntropy);
if (properties.teNumSurrogates > 0)
% Compute the (statistical significance via) null distribution empirically (e.g. with 100 permutations):
measDist = TEcalculator.computeSignificance(properties.teNumSurrogates);
fprintf('Null distribution: %.4f +/- %.4f std dev.; p(surrogate > measured)=%.5f from %d surrogates)\n', ...
measDist.getMeanOfDistribution(), measDist.getStdOfDistribution(), ...
measDist.pValue, properties.teNumSurrogates);
pValue = measDist.pValue;
meanOfSurrogates = measDist.getMeanOfDistribution();
stdOfSurrogates = measDist.getStdOfDistribution();
else
pValue = 1;
meanOfSurrogates = 0;
stdOfSurrogates = 0;
end
if (nargout >= 1)
% Supply the samples back to the caller
% (the caller is probably trying to optimise parameters at the moment)
% Nothing to do then actually...
else
% We're going to save the results instead
% First generate the local values to save as well:
localTranEntropy = TEcalculator.computeLocalOfPreviousObservations(); % local values
% save results
save(properties.resultsFile, 'tranEntropy', 'localTranEntropy', 'pValue', 'meanOfSurrogates', 'stdOfSurrogates', '-append');
fprintf('Transfer entropy saved in %s\n', properties.resultsFile);
end
end

View File

@ -0,0 +1,457 @@
function [D, Dpast, S, RelSourcePos, safeDynamicCorrelationExclusionSamples] = generateObservations(properties)
% This function generates the observations from which
% we can then compute information dynamics with JIDT.
% This will work for either 2D or 3D samples (as specified by the properties)
%
% Author: Emanuele Crosato, Joseph T. Lizier, Sooraj Sekhar, 2019
%
% Inputs:
% - properties (required) - object with properties for the calculations,
% with sub-members as specificied in the loadProperties.m file.
%
% Outputs:
% - D - target samples (may be multivariate as per below)
% - Dpast - target past samples (multivariate, and embedded up to k previous samples)
% - S - source relative headings samples (may be multivariate as per below)
% - RelSourcePos - relative source position (may be multivariate as below)
% - safeDynamicCorrelationExclusionSamples - maximum number of samples with potential dynamic correlation, used for dynamic correlation exclusion externally for the calculations.
% If no outputs are requested, these are saved to properties.resultsFile
%%
%% Java Information Dynamics Toolkit (JIDT)
%% Copyright (C) 2019, Joseph T. Lizier et al.
%%
%% 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/>.
%%
% Call utility to put filename lists in a common format
files = processFilenames(properties.files);
% initialize series for storing the samples:
S = []; % initialise source observations
D = []; % initialise destination observations
Dpast = []; % initialise destination past observations
% only S and D are necessary for lagged mutual information
% all S, D and Dpast are necessary for transfer entropy
fileTimeAndPair = []; % to save time and pair in the format [file_index, time_index, target_index, source_index]
RelSourcePos = []; % initialise relative source positions
sample = 1; % initialise the current sample number
maxSourceSamplesForATarget = 0; % Track the maximum number of in range sources for a given target sample
maxAcfTime = 1; % Track the maximum ACF time for targets
% Need to loop over fileIndex rather than for file = files (which doesn't work properly for cell array of length 1)
for fileIndex = 1:length(files)
dataFileName = files{fileIndex};
% load preprocessed data using the function specified in properties.loadScript
if (properties.data3d)
[x,y,z] = feval(properties.loadScript, dataFileName, properties);
numMissing = sum(sum(isnan([x,y,z])));
else
[x,y] = feval(properties.loadScript, dataFileName, properties);
numMissing = sum(sum(isnan([x,y])));
end
fprintf('Loading data in %s (%d missing values)\n', dataFileName, numMissing);
samplesBeforeThisFile = sample;
% Translate the raw positions into delta Positions
velX = x(2:end,:) - x(1:end-1,:);
velY = y(2:end,:) - y(1:end-1,:);
velXY = sqrt((velX .* velX) + (velY .* velY));
velALL = velXY;
if (properties.data3d)
velZ = z(2:end,:) - z(1:end-1,:);
velALL = sqrt((velXY .* velXY) + (velZ .* velZ));
end
% Translate velocities into headings:
if (properties.data3d)
% Spherical polars:
[headingXY,headingZ,speed] = cart2sph(velX,velY,velZ);
else
% Polar coordinates:
[headingXY,speed] = cart2pol(velX, velY);
end
% Manual way is (can verify these are same except for Nans on x,y and z):
% headingXY = atan(velY ./ velX) + (((velX < 0).*(velY>0)) .* pi) + ...
% (((velX < 0).*(velY<=0)) .* (- pi));
% But the above fails if x and y are *both* zero leaving Nan:
% velYOnVelX = velY ./ velX; % Don't replace all nans in headingXY as some mean missing values
% headingXY(isnan(velYOnVelX(:))) = 0;
% xyMagnitude = sqrt(velX.^2 + velY.^2);
% Since xyMagnitude can only be positive, we can take the straight atan to
% compute headingZ
% headingZ = atan(velZ ./ xyMagnitude);
% get number of fish and update time cycles
numCycles = size(velX,1);
numFish = size(velX,2);
% Calculate the autocorrelation decay time in the changes in headings and the speed:
acfHeadingsDecayTime = zeros(numFish, 1);
acfSpeedDecayTime = zeros(numFish, 1);
for f = 1:numFish
numLags = min(200, size(headingXY,1)-1);
try
% The following sometimes breaks I think if too many Nans
[acfHeading, lags] = autocorr(headingXY(2:end,f) - headingXY(1:end-1,f), 'NumLags', numLags);
catch ME
fprintf('ACF Heading broke for file %d fish %d: either you need to install the Econometrics toolbox (if properties.jidt.autoDynamicCorrelationExclusion = true) or there are too many NaNs in the file\n', fileIndex, f);
continue;
end
acfHeadingsDecayTime(f) = numLags;
for t = 1 : numLags
if (acfHeading(t) < exp(-1))
acfHeadingsDecayTime(f) = t;
break;
end
end
try
[acfSpeed, lags] = autocorr(speed(:,f), 'NumLags', numLags);
catch ME
fprintf('ACF Speed broke for file %d fish %d: either you need to install the Econometrics toolbox (if properties.jidt.autoDynamicCorrelationExclusion = true) or there are too many NaNs in the file\n', fileIndex, f);
continue;
end
acfSpeedDecayTime(f) = numLags;
for t = 1 : numLags
if (acfSpeed(t) < exp(-1))
acfSpeedDecayTime(f) = t;
break;
end
end
end
maxAcfHeadingsDecayTime = mean(acfHeadingsDecayTime); % max(acfHeadingsDecayTime);
maxAcfSpeedDecayTime = mean(acfSpeedDecayTime); % max(acfSpeedDecayTime);
if properties.headingcalc == true
acfTime = maxAcfHeadingsDecayTime;
end
if properties.speedcalc == true
acfTime = maxAcfSpeedDecayTime;
end
if properties.speedcalc == true && properties.headingcalc == true
acfTime = max(maxAcfHeadingsDecayTime, maxAcfSpeedDecayTime);
end
if (acfTime > maxAcfTime)
maxAcfTime = acfTime;
end
fprintf('ACF time of %d from heading %.2f and speed %.2f\n', acfTime, maxAcfHeadingsDecayTime, maxAcfSpeedDecayTime);
% Initialising destPastSample is only important in terms of ensuring it is a row vector.
% If we have 3D data, the vector will get padded out to the appropriate length with the first sample below.
destPastSampleHead = zeros(1, properties.k);
destPastSampleSpeed = zeros(1, properties.k);
startTime = max(1+properties.lag, (properties.k-1)*properties.tau + 3); % Adding 3: one for target, one for first target past, one for taking differences
for i = startTime : numCycles % cycle over time
timePointForSourceHeading = i-properties.lag; % This is indexed into velX and headingXY, hence no extra +1 !
timePointForSourcePosition = i+1-properties.lag; % This is indexed into x not velX, hence the extra +1 !
% Compute relative position of source (at time timePointForSourcePosition) to
% target either at this same time step or the current time at which it is updating.
% Note this position difference is relative to absolute Cartesian coordinates
% (we'll convert to relative to source heading later):
if (properties.sourceWrtSameDestTime)
destPositionTimePointRef = timePointForSourcePosition;
else
destPositionTimePointRef = i;
end
% cycle over fish pairs
for idxFD = 1 : numFish % Target/Destination
% check destination variable
if isnan(headingXY(i,idxFD)) || isnan(headingXY(i-1,idxFD))
continue;
end
if properties.data3d && (isnan(headingZ(i,idxFD)) || isnan(headingZ(i-1,idxFD)))
continue;
end
% check destination past vector
missingFound = false;
for h = 1 : properties.k
idx = i-1-(h-1)*properties.tau;
if isnan(headingXY(idx,idxFD)) || isnan(headingXY(idx-1,idxFD))
missingFound = true;
break;
end
if properties.data3d && (isnan(headingZ(idx,idxFD)) || isnan(headingZ(idx-1,idxFD)))
missingFound = true;
break;
end
end
if missingFound
continue;
end
% Postcondition: All destination variables are ok
% We will create **source** observation as source headings relative to target headings at appropriate time point:
if (properties.sourceWrtSameDestTime)
% Take reference dest heading at same time as source:
theta_FDXY_ref = headingXY(timePointForSourceHeading,idxFD);
else
% Take reference dest heading at prev time step:
theta_FDXY_ref = headingXY(i-1,idxFD);
end
if properties.data3d
if (properties.sourceWrtSameDestTime)
theta_FDZ_ref = headingZ(timePointForSourceHeading,idxFD);
else
theta_FDZ_ref = headingZ(i-1,idxFD);
end
end
% create **destination** observation as change in headings:
if properties.headingcalc == true
theta_FDXY_curr = headingXY(i,idxFD);
theta_FDXY_prev = headingXY(i-1,idxFD);
if properties.data3d
theta_FDZ_curr = headingZ(i,idxFD);
theta_FDZ_prev = headingZ(i-1,idxFD);
destSampleHead = [angleDifference(theta_FDXY_curr, theta_FDXY_prev), ...
angleDifference(theta_FDZ_curr, theta_FDZ_prev)];
else
destSampleHead = angleDifference(theta_FDXY_curr, theta_FDXY_prev);
end
destSample = destSampleHead;
end
if properties.speedcalc == true
destSampleSpeed = velALL(i,idxFD);
destSample = destSampleSpeed;
end
if properties.speedcalc == true && properties.headingcalc == true
destSample = [destSampleHead, destSampleSpeed];
end
% create **destination past** observation as changes in headings at each step:
% TODO: we could take differences to previous sample amongst the k rather than only
% one back from each sample: I'm not sure if this would be a more wholistic embedding or not
% (only makes a difference if tau>1)
if (properties.headingcalc == true)
DpastColIndexHead = 1;
for h = 1 : properties.k
idx = i-1-(h-1)*properties.tau;
theta_FDXY_curr = headingXY(idx,idxFD);
theta_FDXY_prev = headingXY(idx-1,idxFD);
destPastSampleHead(DpastColIndexHead) = angleDifference(theta_FDXY_curr, theta_FDXY_prev);
DpastColIndexHead = DpastColIndexHead + 1;
if properties.data3d
theta_FDZ_curr = headingZ(idx,idxFD);
theta_FDZ_prev = headingZ(idx-1,idxFD);
destPastSampleHead(DpastColIndexHead) = angleDifference(theta_FDZ_curr, theta_FDZ_prev);
DpastColIndexHead = DpastColIndexHead + 1;
end
end
destPastSample = destPastSampleHead;
end
if (properties.speedcalc == true)
DpastColIndexSpeed = 1;
for h = 1 : properties.k
idx = i - 1 - (h - 1) * properties.tau;
destPastSampleSpeed (DpastColIndexSpeed) = velALL(idx,idxFD);
DpastColIndexSpeed = DpastColIndexSpeed + 1;
end
destPastSample = destPastSampleSpeed;
end
if (properties.speedcalc == true && properties.headingcalc == true)
destPastSample = [destPastSampleHead, destPastSampleSpeed];
end
if (isfield(properties, 'destSamplesOnly'))
if (properties.destSamplesOnly)
% User has asked for [D,Dpast] samples only to be returned,
% so we can do these now (without looping over sources):
% Fill in the destination and destination next samples now from above:
D(sample, :) = destSample;
Dpast(sample, :) = destPastSample;
fileTimeAndPair(sample,:) = [fileIndex i idxFD nan];
% increment sample number
sample = sample + 1;
continue; % skip looping over the sources
end
end
numSourceSamplesForThisTarget = 0;
for idxFS = 1 : numFish % Source
% check not the same fish
if (idxFD == idxFS)
continue;
end
relXOfSource = x(timePointForSourcePosition,idxFS) - x(destPositionTimePointRef,idxFD);
relYOfSource = y(timePointForSourcePosition,idxFS) - y(destPositionTimePointRef,idxFD);
if (properties.data3d)
relZOfSource = z(timePointForSourcePosition,idxFS) - z(destPositionTimePointRef,idxFD);
[xyAbsoluteAngleOfSource,zAbsoluteAngleOfSource,distanceBetween] = ...
cart2sph(relXOfSource,relYOfSource,relZOfSource);
else
[xyAbsoluteAngleOfSource,distanceBetween] = ...
cart2pol(relXOfSource,relYOfSource);
end
% Manually: (verified this matches cart2sph):
% xyAbsoluteAngleOfSource = atan(relYOfSource ./ relXOfSource) + ...
% (((relXOfSource < 0).*(relYOfSource>0)) .* pi) + ...
% (((relXOfSource < 0).*(relYOfSource<=0)) .* (- pi));
% xyRelMagnitude = sqrt(relXOfSource.^2 + relYOfSource.^2);
% zAbsoluteAngleOfSource = atan(relZOfSource ./ xyRelMagnitude);
% distanceBetween = sqrt(relXOfSource.^2 + relYOfSource.^2 + ...
% relZOfSource.^2);
% check in range
if (distanceBetween > properties.pairRange)
continue;
end
% check source variable
if isnan(headingXY(timePointForSourceHeading,idxFD)) || isnan(headingXY(timePointForSourceHeading,idxFS))
continue;
end
if properties.data3d && (isnan(headingZ(timePointForSourceHeading,idxFD)) || isnan(headingZ(timePointForSourceHeading,idxFS)))
continue;
end
% Postcondition: There are no missing headings so we can generate an observation.
numSourceSamplesForThisTarget = numSourceSamplesForThisTarget + 1;
% Now compose the data that will be saved for this sample:
% fileTimeAndPair is [file_index, time_index, target_index, source_index]
fileTimeAndPair(sample,:) = [fileIndex i idxFD idxFS];
% create **source** observation as source headings relative to target headings at appropriate time point:
theta_FSXY_lag = headingXY(timePointForSourceHeading,idxFS);
% And convert the absolute angular positions into
% relative angular positions compared to the target's
% heading.
xyRelativeAngleOfSource = angleDifference(...
xyAbsoluteAngleOfSource, ...
theta_FDXY_ref);
if properties.data3d
theta_FSZ_lag = headingZ(timePointForSourceHeading,idxFS);
sourceSampleHeading = [angleDifference(theta_FDXY_ref, theta_FSXY_lag), ...
angleDifference(theta_FDZ_ref, theta_FSZ_lag)];
sourceSample = sourceSampleHeading;
% Elevation angle differences need to be in -pi/2,pi/2 range
zRelativeAngleOfSource = angleDifferencePiOn2(...
zAbsoluteAngleOfSource, ...
theta_FDZ_ref);
% Store these relative polar coordinates of source at timePointForSourcePosition
RelSourcePos(sample,:) = [distanceBetween, xyRelativeAngleOfSource, zRelativeAngleOfSource];
else
sourceSampleHeading = angleDifference(theta_FDXY_ref, theta_FSXY_lag);
sourceSample = sourceSampleHeading;
% Store these relative polar coordinates of source at timePointForSourcePosition
RelSourcePos(sample,:) = [distanceBetween, xyRelativeAngleOfSource];
end
if properties.speedcalc == true
sourceSampleSpeed = velALL(timePointForSourceHeading,idxFS);
sourceSample = sourceSampleSpeed;
end
if properties.speedcalc == true && properties.headingcalc == true
sourceSample = [sourceSampleHeading, sourceSampleSpeed];
end
if properties.includeSourcePositionInTransfer
S(sample,:) = [sourceSample, RelSourcePos(sample,:)];
else
S(sample,:) = sourceSample;
end
% Fill in the destination and destination next samples now from above:
D(sample, :) = destSample;
Dpast(sample, :) = destPastSample;
% increment sample number
sample = sample + 1;
end
if (numSourceSamplesForThisTarget > maxSourceSamplesForATarget)
maxSourceSamplesForATarget = numSourceSamplesForThisTarget;
end
end
% fprintf('Run time step %d\n', i);
end
fprintf(' added %d samples\n', sample - samplesBeforeThisFile);
end
if (sample - 1 == 0)
% We've added no samples
warning('No samples added for the given parameters!');
end
if (isfield(properties, 'destSamplesOnly'))
if (properties.destSamplesOnly)
safeDynamicCorrelationExclusionSamples = maxAcfTime * numFish;
else
safeDynamicCorrelationExclusionSamples = maxAcfTime * numFish * maxSourceSamplesForATarget;
end
end
if (nargout > 1)
% Supply the samples back to the caller
% (the caller is probably trying to optimise parameters at the moment)
% Nothing to do then actually...
else
% We're going to save the samples instead
% display to check
fprintf('Displaying first 5 samples for source, target, target past and fileTimeAndPair as a check:');
disp(S(1:5,:));
disp(D(1:5,:));
disp(Dpast(1:5,:));
disp(fileTimeAndPair(1:5,:));
% input(prompt);
% save series and properties
save(properties.resultsFile, 'S', 'D', 'Dpast', 'files', 'fileTimeAndPair', 'RelSourcePos', ...
'maxSourceSamplesForATarget', 'safeDynamicCorrelationExclusionSamples', 'properties');
fprintf('Series saved in %s (%d samples in total)\n', properties.resultsFile, sample - 1);
end
end
% End function
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% function for computing the difference between two angles.
% the differrence must be between pi and -pi
function [diff] = angleDifference(angleA, angleB)
diff = angleA - angleB; % subtract angles
if abs(diff) > pi % if absolute value is larger than pi
% replace with the complementary angle and switch sign
diff = (2*pi - abs(diff) ) * (-sign(diff));
end
end
% function for computing the difference between two angles in [-pi/2,pi/2].
% the differrence must be returned between pi/2 and -pi/2.
% This is used for differences in elevation angles
function [diff] = angleDifferencePiOn2(angleA, angleB)
diff = angleA - angleB; % subtract angles
% Pre-condition: differences between angles which were in range of
% [-pi/2,pi/2] can only be in range [-pi,pi]
if (diff > pi/2)
diff = pi/2 - (diff - pi/2);
elseif (diff < -pi/2)
diff = -pi/2 + (-pi/2 - diff);
end
end

View File

@ -0,0 +1,75 @@
function [posX,posY] = loadBasic2d(dataFileName, properties)
% This script loads the raw data from a .txt file,
% preprocesses the data and save it as a .mat file.
% The txt data is assumed to have early columns with other data
% (e.g. a timestamp in column 1), with the fish coordinates
% starting from properties.loadBasic2d.startColumn (defaults to 2)
% with fish 1's X and Y coordinates in the first of those columns (defaults to 2 and 3),
% then fish 2's X and Y coordinates in the next of those columns (defaults to 4 and 5),
% and so on.
%%
%% Java Information Dynamics Toolkit (JIDT)
%% Copyright (C) 2019, Joseph T. Lizier et al.
%%
%% 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/>.
%%
% prompt = 'Press a key to continue';
%%% LOAD RAW DATA %%%
%fprintf('Loading data in %s\n', dataFileName); % print to check
% input(prompt);
% read the .txt as a Matlab table (assuming .txt is tab-separated)
data = load(dataFileName);
%fprintf('Size of data is %d - %d\n', ... % print table's size - %d is for int
% size(data,1), size(data,2)); % see also %f (real) and %s (string)
% disp(data(1:5,:)); % display first 10 rows to check
% input(prompt);
%%% FORMAT DATA IN A MORE CONVENIENT WAY %%%
if (nargin == 1) || (~isfield(properties, 'loadBasic2d'))
% Assume the first column is a datestamp
properties.loadBasic2d.startColumn = 2;
end
startCol = properties.loadBasic2d.startColumn;
colsToSkip = startCol - 1;
numFish = (size(data,2)-colsToSkip) ./ 2; % number of fish (we know it from the raw data)
numCycles = size(data,1); % number of time steps (we also know it)
fprintf('Number of fish %d and cycles %d\n', numFish, numCycles);
% prepare variables for x and y position
% as a table [numFish x numCycles]
posX = nan(numCycles,numFish);
posY = nan(numCycles,numFish);
% fill the position tables
for f = 1 : numFish % cycle over all fish
% copy into new variables
posX(:,f) = data(:,startCol+(f-1)*2);
posY(:,f) = data(:,startCol+1+(f-1)*2);
end
% display to check
% disp(size(posX));
% disp(posX(1:5,:));
% disp(size(posY));
% disp(posY(1:5,:));
% input(prompt);

View File

@ -0,0 +1,40 @@
function [x,y] = loadseparatexy(filename, properties)
% loadseparatexy loads 2D fish data from 2 separate txt files (one for x, one for y)
% where in each file time increases down the
% rows and then across the columns we have position columns for each
% fish in turn, i.e. in position x file:
% <fish1x>, <fish2x>, <fish3x>, etc
%
% Inputs:
% - filename - the name template of the file to load, with %s where 'x' and 'y' should be filled in
% - properties (not required) - properties object (may be required for other file loaders)
% Outputs:
% - x - 2D array, each row contains x position for each fish (in columns)
% - y - as per x
%%
%% Java Information Dynamics Toolkit (JIDT)
%% Copyright (C) 2019, Joseph T. Lizier et al.
%%
%% 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/>.
%%
xfilename = sprintf(filename, 'x');
x = load(xfilename);
yfilename = sprintf(filename, 'y');
y = load(yfilename);
end

View File

@ -0,0 +1,43 @@
function [x,y,z] = loadseparatexy(filename, properties)
% loadseparatexy loads 3D fish data from 3 separate txt files (one for x, one for y, one for z)
% where in each file time increases down the
% rows and then across the columns we have position columns for each
% fish in turn, i.e. in position x file:
% <fish1x>, <fish2x>, <fish3x>, etc
%
% Inputs:
% - filename - the name template of the file to load, with %s where 'x', 'y' and 'z' should be filled in
% - properties (not required) - properties object (may be required for other file loaders)
% Outputs:
% - x - 2D array, each row contains x position for each fish (in columns)
% - y - as per x
% - z - as per x
%%
%% Java Information Dynamics Toolkit (JIDT)
%% Copyright (C) 2019, Joseph T. Lizier et al.
%%
%% 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/>.
%%
xfilename = sprintf(filename, 'x');
x = load(xfilename);
yfilename = sprintf(filename, 'y');
y = load(yfilename);
zfilename = sprintf(filename, 'z');
z = load(zfilename);
end

View File

@ -0,0 +1,43 @@
function [x,y] = loadxls2d(filename, properties)
% loadxls2d loads 2D fish data from an xls file where time increases down the
% rows and then across the columns we have 2 x,y position columns for each
% fish in turn, i.e.:
% <timestamp1>, <fish1x>, <fish1y>, <fish2x>, <fish2y>, etc
% <timestamp2>, <fish1x>, <fish1y>, <fish2x>, <fish2y>, etc
%
% Inputs:
% - filename - the name of the file to load
% - properties (not required) - properties object (may be required for other file loaders)
% Outputs:
% - x - 2D array, each row contains x position for each fish (in columns)
% - y - as per x
%%
%% Java Information Dynamics Toolkit (JIDT)
%% Copyright (C) 2019, Joseph T. Lizier et al.
%%
%% 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/>.
%%
[data,txt,raw] = xlsread(filename);
% Make sure we preprocess data to have x,y, as 2D arrays of x(timeStep, fishID):
% timeSteps = size(data,1); % number of rows; not required
xFishIndex = 2 : 2 : size(data,2); % which indices are the x values for different fish
x = data(:,xFishIndex);
y = data(:,xFishIndex+1);
end

View File

@ -0,0 +1,45 @@
function [x,y,z] = loadxls3d(filename, properties)
% loadxls3d loads 3D fish data from an xls file where time increases down the
% rows and then across the columns we have 3 x,y,z position columns for each
% fish in turn, i.e.:
% <timestamp1>, <fish1x>, <fish1y>, <fish1z>, <fish2x>, <fish2y>, <fish2z>, etc
% <timestamp2>, <fish1x>, <fish1y>, <fish1z>, <fish2x>, <fish2y>, <fish2z>, etc
%
% Inputs:
% - filename - the name of the file to load
% - properties (not required) - properties object (may be required for other file loaders)
% Outputs:
% - x - 2D array, each row contains x position for each fish (in columns)
% - y - as per x
% - z - as per x
%%
%% Java Information Dynamics Toolkit (JIDT)
%% Copyright (C) 2019, Joseph T. Lizier et al.
%%
%% 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/>.
%%
[data,txt,raw] = xlsread(filename);
% Make sure we preprocess data to have x,y, and z as 2D arrays of x(timeStep, fishID):
% timeSteps = size(data,1); % number of rows; not required
xFishIndex = 2 : 3 : size(data,2); % which indices are the x values for different fish
x = data(:,xFishIndex);
y = data(:,xFishIndex+1);
z = data(:,xFishIndex+2);
end

View File

@ -0,0 +1,213 @@
function plotLocalTEs(properties)
% Plot the local TEs to show where the information transfer hotspots are from target fish relative to each source
%
% Author: Joseph T. Lizier, 2019
%
% Inputs:
% - properties - object with properties for the calculations,
% with sub-members as specificied in the loadProperties.m file. If not supplied
% the properties are loaded from loadProperties.m
%%
%% Java Information Dynamics Toolkit (JIDT)
%% Copyright (C) 2019, Joseph T. Lizier et al.
%%
%% 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/>.
%%
if (nargin < 1)
fprintf('No properties object supplied, attempting to load properties via a loadProperties script ...');
% By default, just try to load properties locally
if (exist('loadProperties') == 2)
% there is a loadProperties script
loadProperties;
else
% there is not a loadProperties script
error('No properties object supplied, and no loadProperties script found.');
end
end
load(properties.resultsFile);
% Loads:
% S -- source samples
% D -- target samples
% Dpast -- target past samples (embedded up to k previous samples)
% files -- cell array of file names that we took samples from
% fileTimeAndPair -- each row holds file index, time index, target index, source index
% RelSourcePos -- each row holds distance between the pair for this sample,
% their xyRelativeAngleOfSource, and zRelativeAngleOfSource
% lag -- source-target lag that is in use
% k -- embedding length for target that is in use
% tau -- embedding delay for target that is in use
% pairRange -- range within which we've pulled source-target interactions
% tranEntropy -- average transfer entropy
% localTranEntropy -- local TE for each sample
fprintf('%d samples in total for %d fish\n', length(S), length(unique(fileTimeAndPair(:,3))));
relDistance = RelSourcePos(:,1);
relTheta = RelSourcePos(:,2);
% I think this is giving us the right conversions:
if (properties.data3d)
relPhi = RelSourcePos(:,3);
distXY = relDistance .* cos(relPhi);
distZ = relDistance .* sin(relPhi);
else
distXY = relDistance;
end
distInFront = distXY .* cos(relTheta); % X coordinate
distToLeft = distXY .* sin(relTheta); % Y coordinate
% Plot where all the raw positions are:
% Will need to turn this off when we have too many
figure()
% polar(relTheta, distXY, '.r'); % This is equivalent to below:
scatter(distInFront, distToLeft, 2, localTranEntropy);
title('Relative position of source in XY plane for target heading, coloured for TE');
colorbar;
% Plot the density of samples
makePolarBinnedPlot(relTheta, distXY, ones(length(relTheta), 1), 12, 10, true, false);
title('Density of samples in each bin (r_{XY},\theta)');
% Plot the TE in XY plane
makePolarBinnedPlot(relTheta, distXY, localTranEntropy, 12, 10, true, true);
title('Average TE in each bin (r_{XY},\theta)');
% Plot raw positions in phi-z:
% figure()
% polar(relPhi, relDistance, '.r');
% title('Relative position of source in Z-phi plane for target heading');
if (properties.data3d)
% Plot the density of samples in distance-phi plane
makePolarBinnedPlot(relPhi, relDistance, ones(length(relTheta), 1), 12, 10, true, false);
title('Density of samples in each bin (r, \phi)');
% Plot the TE in distance-phi plane
makePolarBinnedPlot(relPhi, relDistance, localTranEntropy, 12, 10, true, true);
title('Average TE in each bin (r, \phi)');
xlabel('r_{XY} [mm]');
ylabel('z [mm]');
end
end
% Inputs:
% - thetas - angles for each sample
% - radii - radius for each sample
% - numAngleBins - how many bins to make across 2*pi
% - numRadialBins - how many bins to make up to the maximum radii
% - useMaxEntBinning - whether to make bins with approx same numbers of points (true)
% or same size (false)
% - plotMean - if true (default) plot the mean within each bin, else plot the total (divded by area)
% The latter is used for densities for example
function makePolarBinnedPlot(thetas, radii, valuesToPlot, numAngleBins, numRadialBins, useMaxEntBinning, plotMean)
if (nargin < 6)
useMaxEntBinning = false;
end
if (nargin < 7)
plotMean = true;
end
if ((min(thetas) < -pi/2) || (max(thetas) > pi/2))
% We're using full angular range -pi : pi
minAngle = -pi;
maxAngle = pi;
extraBinForPlotWrap = true;
else
% We're only using -pi/2:pi/2
minAngle = -pi/2;
maxAngle = pi/2;
extraBinForPlotWrap = false;
end
angleStep = (maxAngle - minAngle) / numAngleBins;
radiusStep = max(radii) / numRadialBins;
% Simple way to do the binning for even bins:
% binnedAngles = floor(thetas ./ angleStep); % Gives the discrete bin for the angle
% binnedRadii = floor(radii ./ radiusStep); % Gives the discrete bin for the radius
% More general, and allowing bins to spread with points:
if (useMaxEntBinning)
% Space the bins for roughly same
% numbers of points (when examined marginally):
sortedAngles = sort(thetas);
binAngleEdges = [minAngle; sortedAngles(floor((1:(numAngleBins-1)).*length(sortedAngles)./numAngleBins)); maxAngle]';
sortedRadii = sort(radii);
binRadiusEdges = [0; sortedRadii(floor((1:(numRadialBins-1)).*length(sortedRadii)./numRadialBins)); max(radii)]';
else
% Space the bins equally
binAngleEdges = minAngle:angleStep:maxAngle;
binRadiusEdges = 0:radiusStep:max(radii);
end
[angleHistCounts,binnedAngles] = histc(thetas, binAngleEdges);
[radiiHistCounts,binnedRadii] = histc(radii, binRadiusEdges);
angleBinValues = 1:numAngleBins; % unique(binnedAngles);
radiusBinValues = 1:numRadialBins; % unique(binnedRadii);
if (extraBinForPlotWrap)
valuesForEachBin = zeros(length(angleBinValues) + 1, length(radiusBinValues));
else
valuesForEachBin = zeros(length(angleBinValues), length(radiusBinValues));
end
numberOfSamples = 0;
for aIndex = 1 : length(angleBinValues)
for rIndex = 1 : length(radiusBinValues)
indicesForThisBin = find((binnedAngles == angleBinValues(aIndex)) & (binnedRadii == radiusBinValues(rIndex)));
if (plotMean)
valueForThisBin = mean(valuesToPlot(indicesForThisBin));
else
% Plot a density: compute total then divide by area.
valueForThisBin = sum(valuesToPlot(indicesForThisBin));
areaOfBin = pi .* (binRadiusEdges(rIndex+1).^2 - binRadiusEdges(rIndex).^2) .* ...
mod(abs(binAngleEdges(aIndex+1) - binAngleEdges(aIndex)), 2.*pi) ./ (2.*pi);
valueForThisBin = valueForThisBin ./ areaOfBin;
end
if (length(indicesForThisBin) == 0)
valueForThisBin = 0;
end
% fprintf('Mean value for r=%.1f+,theta=%.3f+ is %.3f (from %d samples)\n', binRadiusEdges(rIndex), ...
% binAngleEdges(aIndex), valueForThisBin, length(indicesForThisBin));
numberOfSamples = numberOfSamples + length(indicesForThisBin);
valuesForEachBin(aIndex, rIndex) = valueForThisBin;
end
end
% Now convert these so we can plot them:
fprintf('Found %d in total in the bins\n', numberOfSamples);
if (extraBinForPlotWrap)
% And add for first angle again to complete the plot
valuesForEachBin(end,:) = valuesForEachBin(1,:);
[THETA,RR] = meshgrid([(binAngleEdges(1:end-1)+binAngleEdges(2:end))./2, (binAngleEdges(1)+binAngleEdges(2))./2], ...
(binRadiusEdges(1:end-1)+binRadiusEdges(2:end))./2);
else
[THETA,RR] = meshgrid([(binAngleEdges(1:end-1)+binAngleEdges(2:end))./2], ...
(binRadiusEdges(1:end-1)+binRadiusEdges(2:end))./2);
end
[A,B] = pol2cart(THETA,RR);
figure();
% Old way which pinned TE values on the vertices of polygons (looks yuck)
% surf(A,B,valuesForEachBin','edgecolor','none')
% New way, smoothed visualisation:
plot = pcolor(A,B,valuesForEachBin');
plot.FaceColor = 'interp';
set(plot, 'EdgeColor', 'none');
xlabel('x [mm]');
ylabel('y [mm]');
colorbar;
view(0,90)
end

View File

@ -0,0 +1,41 @@
function fileCellArray = processFilenames(fileList)
%
% Turns the fileList from the properties file (usually properties.files) into a cell array of file names. The fileList can be either:
% a. a cell array of file names, e.g.: {'file1.xlsx', 'file2.xlsx'}
% b. a call to ls or ls with an argument, e.g. ls('*.xlsx')
% c. a space or tab separated character row vector of file names
% d. a character matrix of filenames (each filename on a separate row)
%%
%% Java Information Dynamics Toolkit (JIDT)
%% Copyright (C) 2022, Joseph T. Lizier et al.
%%
%% 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/>.
%%
if (iscell(fileList))
% We're done already:
fileCellArray = fileList;
elseif (isvector(fileList))
% We have a row vector of space/tab separate filenames:
fileCellArray = strsplit(strtrim(fileList)); % extra strtrim to remove trailing \n's
elseif (ismatrix(fileList))
fileCellArray = {};
for r = 1 : size(fileList, 1)
fileCellArray{r} = strtrim(fileList(r,:));
end
else
error('fileList appears to be of an incorrect format\n');
end
end

View File

@ -0,0 +1,220 @@
function runAnalysis(properties)
% This high-level function generates the local transfer entropy results, first optimising
% parameters (i.e. embedding length and delay, and source-target lag), then
% storing local transfer entropy values for the optimised parameters.
%
% Author: Joseph T. Lizier, 2019
%
% Inputs:
% - properties (required) - object with properties for the calculations,
% with sub-members as specificied in the loadProperties.m file. If not supplied
% the properties are attempted to be loaded from loadProperties.m
%%
%% Java Information Dynamics Toolkit (JIDT)
%% Copyright (C) 2019, Joseph T. Lizier et al.
%%
%% 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/>.
%%
if (nargin < 1)
fprintf('No properties object supplied, attempting to load properties via a loadProperties script ...');
% By default, just try to load properties locally
if (exist('loadProperties') == 2)
% there is a loadProperties script so attempt to run it to load a properties object
loadProperties;
else
% there is not a loadProperties script
error('No properties object supplied, and no loadProperties script found.');
end
else
% A properties argument was supplied
if (ischar(properties))
% We're assuming it was the name of a properties file
if ((length(properties) > 2) && (strcmp(properties(end-1:end), '.m')))
% Remove the '.m':
properties(end-1:end) = [];
end
if (exist(properties) == 2)
% attempt to run the properties .m file: (after making sure the properties variable is cleared; not necessary but is clean)
propertiesFile = properties;
clear properties;
eval(propertiesFile);
else
error('%s is not an .m file we can find that can be used to load a properties object', properties);
end
% else
% We assume it was the properties object.
end
end
% Step 1: Auto-embed if required:
% Set the lag to 1 as a dummy if we are optimising over that later as well:
if (~isfield(properties, 'lag'))
properties.lag = 1;
end
if (isfield(properties, 'kRange') || isfield(properties, 'tauRange'))
% If any one of these two ranges weren't supplied, set the range variables
% to the value of the corresponding non-range variable:
if (~isfield(properties, 'kRange'))
properties.kRange = properties.k;
end
if (~isfield(properties, 'tauRange'))
properties.tauRange = properties.tau;
end
% Ask generateObservations to only return the target samples for the AIS calculation
properties.destSamplesOnly = true;
% Optimise k and tau
maxAIS = -inf;
maxAISk = properties.kRange(1);
maxAIStau = properties.tauRange(1);
aisForKAndTau = zeros(length(properties.kRange), length(properties.tauRange));
kIndex = 0;
for k = properties.kRange
kIndex = kIndex + 1;
properties.k = k;
minTau = min(properties.tauRange);
tauIndex = 0;
for tau = properties.tauRange
tauIndex = tauIndex + 1;
if ((k == 1) && (tau > minTau))
% We only need compute k=1 for a single tau
continue;
end
properties.tau = tau;
% Generate the observations for k,tau:
[D, Dpast, ~, ~, safeDynamicCorrelationExclusionSamples] = generateObservations(properties);
if (isempty(D))
% There were no samples found for the given parameters, presumably k etc are too long
continue;
end
% Check if we're turning on dynamic correlation exclusion:
if (isfield(properties.jidt, 'autoDynamicCorrelationExclusion'))
properties.jidt.dynamicCorrelationExclusion = safeDynamicCorrelationExclusionSamples;
end
% Compute the AIS:
ais = computeAIS(D, Dpast, properties);
if (ais > maxAIS)
maxAIS = ais;
maxAISk = k;
maxAIStau = tau;
end
aisForKAndTau(kIndex, tauIndex) = ais;
end
end
% Optimisation is complete:
properties.k = maxAISk;
properties.tau = maxAIStau;
properties.ais = maxAIS;
properties.destSamplesOnly = false;
fprintf('*** Optmised k=%d and tau=%d (giving AIS=%.4f - see above for null distribution for these parameters)\n', properties.k, ...
properties.tau, properties.ais);
else
% Hard coded embedding parameters: compute the AIS to be saved anyway :
% Ask generateObservations to only return the target samples for the AIS calculation
properties.destSamplesOnly = true;
[D, Dpast, ~, ~, safeDynamicCorrelationExclusionSamples] = generateObservations(properties);
if (isempty(D))
% There were no samples found for the given parameters, presumably k etc are too long
error('No embeddings possible for the given hard coded k and tau\n');
end
% Check if we're turning on dynamic correlation exclusion:
if (isfield(properties.jidt, 'autoDynamicCorrelationExclusion'))
properties.jidt.dynamicCorrelationExclusion = safeDynamicCorrelationExclusionSamples;
end
% Compute the AIS:
ais = computeAIS(D, Dpast, properties);
properties.ais = ais;
properties.destSamplesOnly = false;
fprintf('*** Hard-coded values for k=%d and tau=%d to be used (giving AIS=%.4f)\n', properties.k, ...
properties.tau, properties.ais);
end
% Check whether to continue to TE calculations:
if (~isfield(properties, 'computeAISOnly'))
properties.computeAISOnly = false;
end
if (properties.computeAISOnly)
fprintf('Finishing after AIS calculation only, as requested.\n');
return;
end
% Step 2: automatically select the correct lag if required:
teNumSurrogates = properties.teNumSurrogates; % Store this for later, turn it off now
properties.teNumSurrogates = 0; % No need to run any surrogates during parameter fitting
if (isfield(properties, 'lagRange'))
% Caller asks us to maximise the TE over a given range:
maxTE = -inf;
maxTElag = properties.lagRange(1);
teForLag = zeros(length(properties.lagRange), 1);
lagIndex = 0;
for lag = properties.lagRange
lagIndex = lagIndex + 1;
properties.lag = lag;
% Generate the observations for k,tau,lag:
[D, Dpast, S, ~, safeDynamicCorrelationExclusionSamples] = generateObservations(properties);
if (isempty(S))
% There were no samples found for the given parameters, presumably k etc are too long
continue;
end
% Check if we're turning on dynamic correlation exclusion:
if (isfield(properties.jidt, 'autoDynamicCorrelationExclusion'))
properties.jidt.dynamicCorrelationExclusion = safeDynamicCorrelationExclusionSamples;
end
% Compute the TE:
te = computeTE(S, D, Dpast, properties);
if (te > maxTE)
maxTE = te;
maxTElag = lag;
end
teForLag(lagIndex) = te;
end
% Optimisation is complete:
properties.lag = maxTElag;
properties.tranEntropy = maxTE;
fprintf('*** Optmised lag=%d (giving TE=%.4f)\n', properties.lag, ...
properties.tranEntropy);
else
fprintf('*** Hard-coded value for lag=%d to be used\n', properties.lag);
end
% 3. Compute TE with the correct parameters
% Now, once again pre-process the positional data into velocities, this time
% saving them into the results file (by not requesting [S,D,Dpast] outputs):
generateObservations(properties);
% And load these samples (S, D, Dpast, properties, maxSourceSamplesForATarget, safeDynamicCorrelationExclusionSamples, etc) in from the saved file:
load(properties.resultsFile);
properties.teNumSurrogates = teNumSurrogates; % Allow surrogates to be computed for this final run with correct parameters
% And compute the TE again for the optimal parameters, this time
% saving the files:
% Turn on dynamic correlation exclusion if required:
if (isfield(properties.jidt, 'autoDynamicCorrelationExclusion'))
if (properties.jidt.autoDynamicCorrelationExclusion)
properties.jidt.dynamicCorrelationExclusion = safeDynamicCorrelationExclusionSamples; % safeDynamicCorrelationExclusionSamples was loaded from the results file
else
properties.jidt.dynamicCorrelationExclusion = 0; % no dynamic correlation exclusion
end
end
% Compute TE with no output arguments so that results are saved
computeTE(S, D, Dpast, properties);
save(properties.resultsFile, 'ais', '-append'); % Add the AIS into the results file as well
if (isfield(properties, 'kRange') || isfield(properties, 'tauRange'))
save(properties.resultsFile, 'aisForKAndTau', '-append'); % Add the AISs computed in auto-embedding
end
if (isfield(properties, 'lagRange'))
save(properties.resultsFile, 'teForLag', '-append'); % Add the TEs computed in optimising the source-target lag
end
end

View File

@ -0,0 +1,151 @@
function watchLocalTEs(dataFileIndex, properties, refreshRate, zoomIn, plotTEIn)
% Plots a movie of local TEs in the swarm from the given input file
%
% Author: Joseph T. Lizier, 2020
%
% Inputs:
% - dataFileIndex - the index of the file to load, from the list of files listed in the properties file. Default 1.
% - properties - object with properties for the calculations,
% with sub-members as specificied in the loadProperties.m file. If not supplied
% the properties are loaded from loadProperties.m
% - refreshRate - how often to change the plotted data (default 0.1 sec)
% - zoomIn - whether to zoom into the individuals (default), or have plot take in whole field
% - plotTEIn - whether to plot the average TE into a target (true, default) or average TE out from a source (false)
%%
%% Java Information Dynamics Toolkit (JIDT)
%% Copyright (C) 2019, Joseph T. Lizier et al.
%%
%% 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/>.
%%
if (nargin < 1)
dataFileIndex = 1;
end
if (nargin < 2)
fprintf('No properties object supplied, attempting to load properties via a loadProperties script ...\n');
% By default, just try to load properties locally
if (exist('loadProperties') == 2)
% there is a loadProperties script
loadProperties;
else
% there is not a loadProperties script
error('No properties object supplied, and no loadProperties script found.');
end
end
load(properties.resultsFile);
% Loads:
% S -- source samples
% D -- target samples
% Dpast -- target past samples (embedded up to k previous samples)
% files -- cell array of file names that we took samples from
% fileTimeAndPair -- each row holds file index, time index, target index, source index
% RelSourcePos -- each row holds distance between the pair for this sample,
% their xyRelativeAngleOfSource, and zRelativeAngleOfSource
% lag -- source-target lag that is in use
% k -- embedding length for target that is in use
% tau -- embedding delay for target that is in use
% pairRange -- range within which we've pulled source-target interactions
% tranEntropy -- average transfer entropy
% localTranEntropy -- local TE for each sample
fprintf('%d samples in total for %d fish\n', length(S), length(unique(fileTimeAndPair(:,3))));
if (nargin < 3)
refreshRate = 0.1;
end
% Call utility to put filename lists in a common format
files = processFilenames(properties.files);
dataFileName = files{dataFileIndex};
% load preprocessed data using the function specified in properties.loadScript
if (properties.data3d)
[x,y,z] = feval(properties.loadScript, dataFileName, properties);
numMissing = sum(sum(isnan([x,y,z])));
maxZ = max(z(:));
minZ = min(z(:));
else
[x,y] = feval(properties.loadScript, dataFileName, properties);
numMissing = sum(sum(isnan([x,y])));
end
maxX = max(x(:));
minX = min(x(:));
maxY = max(y(:));
minY = min(y(:));
if (nargin < 4)
zoomIn = true;
end
figure()
if (~zoomIn)
fprintf('Focussing...\n');
if (properties.data3d)
axis([minX, maxX, minY, maxY, minZ, maxZ]);
else
axis([minX, maxX, minY, maxY]);
end
% Need to set this so that the axes don't keep updating
end
fprintf('%d missing values\n', numMissing);
if (nargin < 5)
plotTEIn = true;
end
% Work out the range of TEs for this data file:
teMin = min(localTranEntropy(find(fileTimeAndPair(:,1) == dataFileIndex)));
teMax = max(localTranEntropy(find(fileTimeAndPair(:,1) == dataFileIndex)));
% Loop over all the time steps in this data file
numFish = size(x,2);
cb = colorbar;
xlabel('x');
ylabel('y');
cb.Label.String = 'Av local TE';
% caxis([teMin teMax]); % These are likely too extreme for the averages
for t = 1:size(x, 1)
set(gca,'NextPlot','replacechildren') ;
% Now loop over all fish as either source or target:
averageTEs = zeros(1,numFish);
for f = 1:numFish
% Find which interactions involve TE into or out from this fish at this time step
if (plotTEIn)
% For TE in, match the target:
rowIDs = find((fileTimeAndPair(:,1) == dataFileIndex) & (fileTimeAndPair(:,2) == t) & ...
(fileTimeAndPair(:,3) == f));
else
% For TE out, match the source:
rowIDs = find((fileTimeAndPair(:,1) == dataFileIndex) & (fileTimeAndPair(:,2) == t) & ...
(fileTimeAndPair(:,4) == f));
end
% Now average the TE into or out of this fish:
averageTEs(f) = mean(localTranEntropy(rowIDs));
end
if (properties.data3d)
scatter3(x(t,:), y(t,:), z(t,:), 5, averageTEs);
else
scatter(x(t,:), y(t,:), 5, averageTEs)
end
if (plotTEIn)
title(sprintf('Average TEs into each individual at time %d, coloured for TE', t));
else
title(sprintf('Average TEs out from each individual at time %d, coloured for TE', t));
end
pause(refreshRate)
end
end

View File

@ -0,0 +1,74 @@
function watchRawMovement(dataFileName, properties, refreshRate, zoomIn)
% Plots a movie of raw movement data from the given input file
%
% Author: Joseph T. Lizier, 2020
%
% Inputs:
% - dataFileName - the name of the file to load
% - properties - properties object
% - refreshRate - how often to change the plotted data (default 0.1 sec)
% - zoomIn - whether to zoom into the individuals (default), or have plot take in whole field
%%
%% Java Information Dynamics Toolkit (JIDT)
%% Copyright (C) 2019, Joseph T. Lizier et al.
%%
%% 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/>.
%%
if (nargin < 3)
refreshRate = 0.1;
end
if (nargin < 4)
zoomIn = true;
end
% load preprocessed data using the function specified in properties.loadScript
if (properties.data3d)
[x,y,z] = feval(properties.loadScript, dataFileName, properties);
numMissing = sum(sum(isnan([x,y,z])));
maxZ = max(z(:));
minZ = min(z(:));
else
[x,y] = feval(properties.loadScript, dataFileName, properties);
numMissing = sum(sum(isnan([x,y])));
end
maxX = max(x(:));
minX = min(x(:));
maxY = max(y(:));
minY = min(y(:));
if (~zoomIn)
fprintf('Focussing...\n');
if (properties.data3d)
axis([minX, maxX, minY, maxY, minZ, maxZ]);
else
axis([minX, maxX, minY, maxY]);
end
% Need to set this so that the axes don't keep updating
end
fprintf('Loading data in %s (%d missing values)\n', dataFileName, numMissing);
for t = 1:size(x, 1)
set(gca,'NextPlot','replacechildren') ;
if (properties.data3d)
plot3(x(t,:), y(t,:), z(t,:), 'x')
else
plot(x(t,:), y(t,:), 'x')
end
pause(refreshRate)
end
end

15
demos/octave/javaMatrixToOctave.m Executable file → Normal file
View File

@ -47,7 +47,12 @@ function octaveMatrix = javaMatrixToOctave(javaMatrix, startRow, startCol, numRo
% Convert whole matrix first:
tmp = javaObject('org.octave.Matrix', javaMatrix);
% Make sure tmp.ident() is converted to native octave:
oldFlag = java_convert_matrix (1);
if (exist('java_matrix_autoconversion') > 0)
oldFlag = java_matrix_autoconversion (1);
else
% Must be old octave version:
oldFlag = java_convert_matrix (1);
end
converted = false;
unwind_protect
octaveMatrix = tmp.ident(tmp);
@ -55,7 +60,12 @@ function octaveMatrix = javaMatrixToOctave(javaMatrix, startRow, startCol, numRo
unwind_protect_cleanup
% restore to non-default conversion, otherwise we get
% bad errors on other calls
java_convert_matrix(oldFlag);
if (exist('java_matrix_autoconversion') > 0)
java_matrix_autoconversion(oldFlag);
else
% Must be old octave version:
java_convert_matrix(oldFlag);
end
end_unwind_protect
if (converted)
if (nargin >= 2)
@ -67,6 +77,7 @@ function octaveMatrix = javaMatrixToOctave(javaMatrix, startRow, startCol, numRo
else
% Else we're in matlab, in which case the native java type can be handled, so return it directly:
octaveMatrix = javaMatrix;
return;
end
% Else, we encountered an error in the octave resizing, so fall through to element by element conversion:

View File

@ -32,7 +32,12 @@ function jIntArray = octaveToJavaIntArray(octaveArray)
if (length(octaveArray) > 1)
% Do this the normal way
tmp = javaObject('infodynamics.utils.OctaveMatrix');
tmp.loadIntData(octaveArray,[1, length(octaveArray)]);
try
tmp.loadIntData(octaveArray,[1, length(octaveArray)]);
catch
% Most likely error here is that octaveArray is interpreted as booleans, so try loading as booleans:
tmp.loadBooleanAsIntData(octaveArray,[1, length(octaveArray)]);
end
jIntArray = tmp.asIntVector();
else
% For length 1 arrays, we need to perform a hack here or else

View File

@ -32,7 +32,12 @@ function jIntMatrix = octaveToJavaIntMatrix(octaveMatrix)
if ((rows(octaveMatrix)*columns(octaveMatrix)) > 1)
% Do this the normal way
tmp = javaObject('infodynamics.utils.OctaveMatrix');
tmp.loadIntData(reshape(octaveMatrix,1,rows(octaveMatrix)*columns(octaveMatrix)),[rows(octaveMatrix), columns(octaveMatrix)]);
try
tmp.loadIntData(reshape(octaveMatrix,1,rows(octaveMatrix)*columns(octaveMatrix)),[rows(octaveMatrix), columns(octaveMatrix)]);
catch
% Most likely error here is that octaveMatrix is interpreted as booleans, so try loading as booleans:
tmp.loadBooleanAsIntData(reshape(octaveMatrix,1,rows(octaveMatrix)*columns(octaveMatrix)),[rows(octaveMatrix), columns(octaveMatrix)]);
end
jIntMatrix = tmp.asIntMatrix();
else
% For length 1 arrays, we need to perform a hack here or else

View File

@ -0,0 +1,259 @@
# Argument order: network_type_name num_spikes sim_number target_index
from jpype import *
import random
import math
import os
import numpy as np
import pickle
import copy
import sys
# net_type_name is useful if you are iterating over multiple files with different network types.
# Looking at the definition of SPIKES_FILE_NAME and OUTPUT_FILE_PREFIX will imply what the purpose of
# these command line arguments is.
net_type_name = sys.argv[1]
num_spikes_string = sys.argv[2]
repeat_num_string = sys.argv[3]
target_index_string = sys.argv[4]
# The number of surrogates to create for each significance test of a TE value
NUM_SURROGATES_PER_TE_VAL = 100
# The p level below which the null hypothesis will be rejected.
P_LEVEL = 0.05
# The number of nearest neighbours to consider in the TE estimation.
KNNS = 10
# The number of random sample points laid down will be NUM_SAMPLES_MULTIPLIER * length_of_target_train
NUM_SAMPLES_MULTIPLIER = 5.0
#SURROGATE_NUM_SAMPLES_MULTIPLIER = 5.0
# As above, but for the creation of surrogates
SURROGATE_NUM_SAMPLES_MULTIPLIER = 5.0
# The number of nearest neighbours to consider when using the local permutation method to create surrogates
K_PERM = 20
# The level of the noise to add to the random sample points used in creating surrogates
JITTERING_LEVEL = 2000
# When MAX_NUM_SECOND_INTERVALS sources have 2 or more history intervals added into the conditioning set, the inference stops
MAX_NUM_SECOND_INTERVALS = 2
# Exclude target spikes beyond this number
MAX_NUM_TARGET_SPIKES = int(num_spikes_string)
# The spikes file with the below name is expected to contain a single pickled Python list. This list contains numpy arrays. Each
# numpy array contains the spike times of each candidate target.
SPIKES_FILE_NAME = "spikes_LIF_" + net_type_name + "_" + repeat_num_string + ".pk"
# The ground truth file of the below name is expected to contain a single pickled Python list. This list contains tuples of the format(source, target).
# source and target are integers of the indices of true connections.
GROUND_TRUTH_FILE_NAME = "connections_LIF_"+ net_type_name + "_" + repeat_num_string + ".pk"
OUTPUT_FILE_PREFIX = "results/inferred_sources_target_2_" + net_type_name + "_" + num_spikes_string + "_" + repeat_num_string + "_" + target_index_string
LOG_FILE_NAME = "logs/" + net_type_name + "_" + num_spikes_string + "_" + repeat_num_string + "_" + target_index_string + ".log"
log = open(LOG_FILE_NAME, "w")
sys.stdout = log
def prepare_conditional_trains(calc_object, cond_set, spikes):
cond_trains = []
calc_object.clearConditionalIntervals()
if len(cond_set) > 0:
for key in cond_set.keys():
cond_trains.append(spikes[key])
calc_object.appendConditionalIntervals(JArray(JInt, 1)(cond_set[key]))
return cond_trains
def set_target_embeddings(embedding_list, calc_object):
if len(embedding_list) > 0:
embedding_string = str(embedding_list[0])
for i in range(2, len(embedding_list)):
embedding_string += "," + str(embedding_list[i])
calc_object.setProperty("DEST_PAST_INTERVALS", embedding_string)
else:
calc_object.setProperty("DEST_PAST_INTERVALS", "")
target_index = int(target_index_string)
print("\n****** Network inference for target neuron", target_index, "******\n\n")
# Setup JIDT
jarLocation = os.path.join(os.getcwd(), "../jidt/infodynamics.jar");
if (not(os.path.isfile(jarLocation))):
exit("infodynamics.jar not found (expected at " + os.path.abspath(jarLocation) + ") - are you running from demos/python?")
startJVM(getDefaultJVMPath(), "-ea", "-Djava.class.path=" + jarLocation)
teCalcClass = JPackage("infodynamics.measures.spiking.integration").TransferEntropyCalculatorSpikingIntegration
teCalc = teCalcClass()
teCalc.setProperty("knns", str(KNNS))
teCalc.setProperty("NUM_SAMPLES_MULTIPLIER", str(NUM_SAMPLES_MULTIPLIER))
teCalc.setProperty("SURROGATE_NUM_SAMPLES_MULTIPLIER", str(SURROGATE_NUM_SAMPLES_MULTIPLIER))
teCalc.setProperty("K_PERM", str(K_PERM))
teCalc.setProperty("DO_JITTERED_SAMPLING", "true")
teCalc.setProperty("JITTERED_SAMPLING_NOISE_LEVEL", str(JITTERING_LEVEL))
# Load spikes and ground truth connectivity
spikes = pickle.load(open(SPIKES_FILE_NAME, 'rb'))
cons = pickle.load(open(GROUND_TRUTH_FILE_NAME, 'rb'))
if MAX_NUM_TARGET_SPIKES < len(spikes[target_index]):
spikes[target_index] = spikes[target_index][:MAX_NUM_TARGET_SPIKES]
print("Number of target spikes: ", len(spikes[target_index]), "\n\n")
# First determine the correct target embedding
target_embedding_set = [1]
next_target_interval = 2
still_significant = True
print("**** Determining target embedding set ****\n")
while still_significant:
set_target_embeddings(target_embedding_set, teCalc)
teCalc.setProperty("SOURCE_PAST_INTERVALS", str(next_target_interval))
teCalc.startAddObservations()
teCalc.addObservations(JArray(JDouble, 1)(spikes[target_index]), JArray(JDouble, 1)(spikes[target_index]))
teCalc.finaliseAddObservations();
TE = teCalc.computeAverageLocalOfObservations()
sig = teCalc.computeSignificance(NUM_SURROGATES_PER_TE_VAL, TE)
print("candidate interval:", next_target_interval, " TE:", TE, " p val:", sig.pValue)
if sig.pValue > P_LEVEL:
print("Lost significance, end of target embedding determination")
still_significant = False
else:
target_embedding_set.append(next_target_interval)
next_target_interval += 1
print("target embedding set:", target_embedding_set, "\n\n")
# Now add the sources
# cond_set is a dictionary where keys are added sources and values are lists of included intervals for the
# source key.
cond_set = dict()
# next_interval_for_each_candidate will be a matrix with two columns
# first column has the source indices, second has the next interval that will be considered
next_interval_for_each_candidate = np.arange(0, len(spikes), dtype = np.intc)
next_interval_for_each_candidate = next_interval_for_each_candidate[next_interval_for_each_candidate != target_index]
next_interval_for_each_candidate = np.column_stack((next_interval_for_each_candidate, np.ones(len(next_interval_for_each_candidate), dtype = np.intc)))
still_significant = True
TE_vals_at_each_round = []
surrogate_vals_at_each_round = []
print("**** Adding Sources ****\n")
num_twos = 0
while still_significant:
print("Current conditioning set:")
for key in cond_set.keys():
print("source", key, "intervals", cond_set[key])
print("\nEstimating TE on candidate sources")
cond_trains = prepare_conditional_trains(teCalc, cond_set, spikes)
TE_vals = np.zeros(next_interval_for_each_candidate.shape[0])
debiased_TE_vals = -1 * np.ones(next_interval_for_each_candidate.shape[0])
surrogate_vals = -1 * np.ones((next_interval_for_each_candidate.shape[0], NUM_SURROGATES_PER_TE_VAL))
debiased_surrogate_vals = 1 - np.ones((next_interval_for_each_candidate.shape[0], NUM_SURROGATES_PER_TE_VAL))
is_con = np.zeros(next_interval_for_each_candidate.shape[0])
for i in range(next_interval_for_each_candidate.shape[0]):
if len(spikes[next_interval_for_each_candidate[i, 0]]) < 10:
continue
teCalc.startAddObservations()
teCalc.setProperty("SOURCE_PAST_INTERVALS", str(next_interval_for_each_candidate[i, 1]))
if len(cond_set) > 0:
teCalc.addObservations(JArray(JDouble, 1)(spikes[next_interval_for_each_candidate[i, 0]]),
JArray(JDouble, 1)(spikes[target_index]), JArray(JDouble, 2)(cond_trains))
else:
teCalc.addObservations(JArray(JDouble, 1)(spikes[next_interval_for_each_candidate[i, 0]]),
JArray(JDouble, 1)(spikes[target_index]))
teCalc.finaliseAddObservations();
TE_vals[i] = teCalc.computeAverageLocalOfObservations()
is_con[i] = ([next_interval_for_each_candidate[i, 0], target_index] in cons)
sig = teCalc.computeSignificance(NUM_SURROGATES_PER_TE_VAL, TE_vals[i])
surrogate_vals[i] = sig.distribution
debiased_TE_vals[i] = TE_vals[i] - np.mean(surrogate_vals[i])
debiased_surrogate_vals[i] = sig.distribution - np.mean(surrogate_vals[i])
print("Source", next_interval_for_each_candidate[i, 0], "Interval", next_interval_for_each_candidate[i, 1],
" TE:", str(debiased_TE_vals[i]))
log.flush()
TE_vals_at_each_round.append(TE_vals)
surrogate_vals_at_each_round.append(surrogate_vals)
sorted_TE_indices = np.argsort(debiased_TE_vals)
print("\nSorted order of sources:\n", next_interval_for_each_candidate[:, 0][sorted_TE_indices[:]])
print("Ground truth for sorted order:\n", is_con[sorted_TE_indices[:]])
index_of_max_candidate = sorted_TE_indices[-1]
samples_from_max_dist = np.max(debiased_surrogate_vals, axis = 0)
np.sort(samples_from_max_dist)
index_of_first_greater_than_estimate = np.searchsorted(samples_from_max_dist > debiased_TE_vals[index_of_max_candidate], 1)
p_val = (NUM_SURROGATES_PER_TE_VAL - index_of_first_greater_than_estimate)/float(NUM_SURROGATES_PER_TE_VAL)
print("\nMaximum candidate is source", next_interval_for_each_candidate[index_of_max_candidate, 0],
"interval", next_interval_for_each_candidate[index_of_max_candidate, 1])
print("p: ", p_val)
if p_val <= P_LEVEL:
if (next_interval_for_each_candidate[index_of_max_candidate, 0]) in cond_set:
cond_set[next_interval_for_each_candidate[index_of_max_candidate, 0]].append(next_interval_for_each_candidate[index_of_max_candidate, 1])
else:
cond_set[next_interval_for_each_candidate[index_of_max_candidate, 0]] = [next_interval_for_each_candidate[index_of_max_candidate, 1]]
if next_interval_for_each_candidate[index_of_max_candidate, 1] == 2:
num_twos += 1
if num_twos >= MAX_NUM_SECOND_INTERVALS:
print("\nMaximum number of second intervals reached\n\n")
still_significant = False
next_interval_for_each_candidate[index_of_max_candidate, 1] += 1
print("\nCandidate added\n\n")
else:
still_significant = False
print("\nLost Significance\n\n")
print("**** Pruning Sources ****\n")
# Repeatedly removes the connection that has the lowest TE out of all insignificant connections.
# Only considers the furthest intervals as candidates in each round.
everything_significant = False
while not everything_significant:
print("Current conditioning set:")
for key in cond_set.keys():
print("source", key, "intervals", cond_set[key])
print("\nEstimating TE on candidate sources")
everything_significant = True
insignificant_sources = []
insignificant_sources_TE = []
for candidate_source in cond_set:
cond_set_minus_candidate = copy.deepcopy(cond_set)
# If more than one interval, remove the last
if len(cond_set_minus_candidate[candidate_source]) > 1:
cond_set_minus_candidate[candidate_source] = cond_set_minus_candidate[candidate_source][:-1]
# Otherwise, remove source from dict
else:
cond_set_minus_candidate.pop(candidate_source)
teCalc.setProperty("SOURCE_PAST_INTERVALS", str(cond_set[candidate_source][-1]))
cond_trains = prepare_conditional_trains(teCalc, cond_set_minus_candidate, spikes)
teCalc.startAddObservations()
if len(cond_set_minus_candidate) > 0:
teCalc.addObservations(JArray(JDouble, 1)(spikes[candidate_source]), JArray(JDouble, 1)(spikes[target_index]), JArray(JDouble, 2)(cond_trains))
else:
teCalc.addObservations(JArray(JDouble, 1)(spikes[candidate_source]), JArray(JDouble, 1)(spikes[target_index]))
teCalc.finaliseAddObservations();
TE = teCalc.computeAverageLocalOfObservations()
sig = teCalc.computeSignificance(NUM_SURROGATES_PER_TE_VAL, TE)
print("Source", candidate_source, "Interval", cond_set[candidate_source][-1],
" TE:", str(round(TE, 2)), " p val:", sig.pValue)
if sig.pValue > P_LEVEL:
everything_significant = False
insignificant_sources.append(candidate_source)
insignificant_sources_TE.append(TE)
if not everything_significant:
min_TE_source = insignificant_sources[np.argmin(insignificant_sources_TE)]
print("removing source", min_TE_source, "interval", cond_set[min_TE_source][-1])
if len(cond_set[min_TE_source]) > 1:
cond_set[min_TE_source] = cond_set[min_TE_source][:-1]
else:
cond_set.pop(min_TE_source)
print("\n\n****** Final Inferred Source Set ******\n")
for key in cond_set.keys():
print("source", key, "intervals", cond_set[key])
print("\nTrue Sources:")
for con in cons:
if con[1] == target_index:
print(con[0], " ",)
output_file = open(OUTPUT_FILE_PREFIX + ".pk", 'wb')
pickle.dump(cond_set, output_file)
#pickle.dump(surrogate_vals_at_each_round, output_file)
#pickle.dump(TE_vals_at_each_round, output_file)
output_file.close()

View File

@ -0,0 +1,46 @@
# This script converts CSV files of spike times (e.g. from the Wagenaar data set) into
# pickle files of spike times in the format that the net_inf.py script expects
import numpy as np
import pickle
import sys
import ast
import matplotlib.pyplot as plt
RUN = "1-1-20.2"
spk_file = open('extracted_data_wagenaar/1-1/' + RUN + '.spk', 'r')
time_upper = 8 * 60 * 60 * 2.5e4
spikes = []
for line in spk_file:
line = line.strip()
line = line.split(",")
line = [float(time) for time in line if time != ""]
spikes.append(np.array(line))
start_times = [train[0] for train in spikes if len(train) > 0]
lowest_start_time = min(start_times)
cutoff_time = lowest_start_time + time_upper
for i in range(len(spikes)):
spikes[i] = spikes[i][spikes[i] < cutoff_time]
spikes[i] = spikes[i] - lowest_start_time
spikes[i] = spikes[i] + np.random.uniform(size = spikes[i].shape) - 0.5
spikes[i] = np.sort(spikes[i])
print(len(spikes))
for i in range(len(spikes)):
print(spikes[i].shape)
print(spikes[i][:10])
#plt.eventplot(spikes, linewidth = 0.5)
#plt.show()
spikes_file = open("spikes_LIF_" + RUN + "_" + sys.argv[1] + ".pk", "wb")
pickle.dump(spikes, spikes_file)
cons = [[0, 0]]
connections_file = open("connections_LIF_" + RUN + "_" + sys.argv[1] + ".pk", "wb")
pickle.dump(cons, connections_file)
spikes_file.close()
connections_file.close()

BIN
demos/python/README-PythonDemos.pdf Executable file → Normal file

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,191 @@
##
## Java Information Dynamics Toolkit (JIDT)
## Copyright (C) 2022, David P. Shorten, 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/>.
##
# Transfer entropy (TE) calculation on generated spike train data using the continuous-time TE estimator.
from jpype import *
import random
import math
import os
import numpy as np
NUM_REPS = 2
NUM_SPIKES = int(2e3)
NUM_OBSERVATIONS = 2
NUM_SURROGATES = 10
# Params for canonical example generation
RATE_Y = 1.0
RATE_X_MAX = 10
def generate_canonical_example_processes(num_y_events):
event_train_x = []
event_train_x.append(0)
event_train_y = np.random.uniform(0, int(num_y_events / RATE_Y), int(num_y_events))
event_train_y.sort()
most_recent_y_index = 0
previous_x_candidate = 0
while most_recent_y_index < (len(event_train_y) - 1):
this_x_candidate = previous_x_candidate + random.expovariate(RATE_X_MAX)
while most_recent_y_index < (len(event_train_y) - 1) and this_x_candidate > event_train_y[most_recent_y_index + 1]:
most_recent_y_index += 1
delta_t = this_x_candidate - event_train_y[most_recent_y_index]
rate = 0
if delta_t > 1:
rate = 0.5
else:
rate = 0.5 + 5.0 * math.exp(-50 * (delta_t - 0.5)**2) - 5.0 * math.exp(-50 * (0.5)**2)
if random.random() < rate/float(RATE_X_MAX):
event_train_x.append(this_x_candidate)
previous_x_candidate = this_x_candidate
event_train_x.sort()
event_train_y.sort()
return event_train_x, event_train_y
# Change location of jar to match yours (we assume script is called from demos/python):
jarLocation = os.path.join(os.getcwd(), "infodynamics.jar");
if (not(os.path.isfile(jarLocation))):
exit("infodynamics.jar not found (expected at " + os.path.abspath(jarLocation) + ") - are you running from demos/python?")
# 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)
teCalcClass = JPackage("infodynamics.measures.spiking.integration").TransferEntropyCalculatorSpikingIntegration
teCalc = teCalcClass()
teCalc.setProperty("knns", "4")
print("Independent Poisson Processes")
teCalc.setProperty("DEST_PAST_INTERVALS", "1,2")
teCalc.setProperty("SOURCE_PAST_INTERVALS", "1,2")
# It is recommended that this is never set to 'true', apart from cases of extremely bursty spiking (that is, long periods
# of no activity and short periods of intense spiking). In such cases, care must also be taken in the setting of the
# parameter JITTERED_SAMPLING_NOISE_LEVEL.
teCalc.setProperty("DO_JITTERED_SAMPLING", "false")
teCalc.appendConditionalIntervals(JArray(JInt, 1)([1, 2]))
teCalc.appendConditionalIntervals(JArray(JInt, 1)([1, 2]))
teCalc.setProperty("NORM_TYPE", "MAX_NORM")
results_poisson = np.zeros(NUM_REPS)
for i in range(NUM_REPS):
teCalc.startAddObservations()
for j in range(NUM_OBSERVATIONS):
sourceArray = NUM_SPIKES*np.random.random(NUM_SPIKES)
sourceArray.sort()
destArray = NUM_SPIKES*np.random.random(NUM_SPIKES)
destArray.sort()
condArray = NUM_SPIKES*np.random.random((2, NUM_SPIKES))
condArray.sort(axis = 1)
teCalc.addObservations(JArray(JDouble, 1)(sourceArray), JArray(JDouble, 1)(destArray), JArray(JDouble, 2)(condArray))
teCalc.finaliseAddObservations();
result = teCalc.computeAverageLocalOfObservations()
print("TE result %.4f nats" % (result,))
sig = teCalc.computeSignificance(NUM_SURROGATES, result)
print(sig.pValue)
results_poisson[i] = result
print("Summary: mean ", np.mean(results_poisson), " std dev ", np.std(results_poisson))
teCalc = teCalcClass()
teCalc.setProperty("knns", "4")
print("Noisy copy zero TE")
#teCalc.appendConditionalIntervals(JArray(JInt, 1)([1]))
teCalc.setProperty("DEST_PAST_INTERVALS", "1")
teCalc.setProperty("SOURCE_PAST_INTERVALS", "1")
teCalc.setProperty("DO_JITTERED_SAMPLING", "false")
#teCalc.setProperty("NORM_TYPE", "MAX_NORM")
results_noisy_zero = np.zeros(NUM_REPS)
for i in range(NUM_REPS):
teCalc.startAddObservations()
for j in range(NUM_OBSERVATIONS):
condArray = np.ones((1, NUM_SPIKES)) + 0.05 * np.random.random((1, NUM_SPIKES))
condArray = np.cumsum(condArray, axis = 1)
condArray.sort(axis = 1)
sourceArray = condArray[0, :] + 0.25 + 0.05 * np.random.normal(size = condArray.shape[1])
sourceArray.sort()
destArray = condArray[0, :] + 0.5 + 0.05 * np.random.normal(size = condArray.shape[1])
destArray.sort()
#teCalc.addObservations(JArray(JDouble, 1)(sourceArray), JArray(JDouble, 1)(destArray), JArray(JDouble, 2)(condArray))
teCalc.addObservations(JArray(JDouble, 1)(sourceArray), JArray(JDouble, 1)(destArray))
teCalc.finaliseAddObservations();
result = teCalc.computeAverageLocalOfObservations()
print("TE result %.4f nats" % (result,))
sig = teCalc.computeSignificance(NUM_SURROGATES, result)
print(sig.pValue)
results_noisy_zero[i] = result
print("Summary: mean ", np.mean(results_noisy_zero), " std dev ", np.std(results_noisy_zero))
teCalc = teCalcClass()
teCalc.setProperty("knns", "4")
print("Noisy copy non-zero TE")
teCalc.appendConditionalIntervals(JArray(JInt, 1)([1]))
teCalc.setProperty("DEST_PAST_INTERVALS", "1,2")
teCalc.setProperty("SOURCE_PAST_INTERVALS", "1")
teCalc.setProperty("DO_JITTERED_SAMPLING", "false")
#teCalc.setProperty("NORM_TYPE", "MAX_NORM")
results_noisy_non_zero = np.zeros(NUM_REPS)
for i in range(NUM_REPS):
teCalc.startAddObservations()
for j in range(NUM_OBSERVATIONS):
sourceArray = np.ones((1, NUM_SPIKES)) + 0.05 * np.random.random((1, NUM_SPIKES))
sourceArray = np.cumsum(sourceArray)
sourceArray.sort()
condArray = sourceArray + 0.25 + 0.05 * np.random.normal(size = sourceArray.shape)
condArray.sort()
condArray = np.expand_dims(condArray, 0)
destArray = sourceArray + 0.5 + 0.05 * np.random.normal(size = sourceArray.shape)
destArray.sort()
teCalc.addObservations(JArray(JDouble, 1)(sourceArray), JArray(JDouble, 1)(destArray), JArray(JDouble, 2)(condArray))
teCalc.finaliseAddObservations();
result = teCalc.computeAverageLocalOfObservations()
print("TE result %.4f nats" % (result,))
sig = teCalc.computeSignificance(NUM_SURROGATES, result)
print(sig.pValue)
results_noisy_non_zero[i] = result
print("Summary: mean ", np.mean(results_noisy_non_zero), " std dev ", np.std(results_noisy_zero))
print("Canonical example")
teCalc = teCalcClass()
teCalc.setProperty("knns", "4")
teCalc.setProperty("DEST_PAST_INTERVALS", "1,2")
teCalc.setProperty("SOURCE_PAST_INTERVALS", "1")
teCalc.setProperty("DO_JITTERED_SAMPLING", "false")
#teCalc.setProperty("NUM_SAMPLES_MULTIPLIER", "1")
#teCalc.setProperty("NORM_TYPE", "MAX_NORM")
results_canonical = np.zeros(NUM_REPS)
for i in range(NUM_REPS):
event_train_x, event_train_y = generate_canonical_example_processes(NUM_SPIKES)
teCalc.setObservations(JArray(JDouble, 1)(event_train_y), JArray(JDouble, 1)(event_train_x))
result = teCalc.computeAverageLocalOfObservations()
results_canonical[i] = result
print("TE result %.4f nats" % (result,))
sig = teCalc.computeSignificance(NUM_SURROGATES, result)
print(sig.pValue)
print("Summary: mean ", np.mean(results_canonical), " std dev ", np.std(results_canonical))

87
demos/python/create_env.bat Executable file
View File

@ -0,0 +1,87 @@
@ECHO OFF
REM
REM Java Information Dynamics Toolkit (JIDT)
REM Copyright (C) 2022, Joseph T. Lizier
REM
REM This program is free software: you can redistribute it and/or modify
REM it under the terms of the GNU General Public License as published by
REM the Free Software Foundation, either version 3 of the License, or
REM (at your option) any later version.
REM
REM This program is distributed in the hope that it will be useful,
REM but WITHOUT ANY WARRANTY; without even the implied warranty of
REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
REM GNU General Public License for more details.
REM
REM You should have received a copy of the GNU General Public License
REM along with this program. If not, see <http://www.gnu.org/licenses/>.
REM
REM Create a python environment (stored in folder %folder%) with jpype1, numpy and scipy installed
REM Name of folder to use and python commands -- change if required:
set folder=jpype_env
set pythonCmd=python
set pipCmd=pip
REM First make sure that the virtualenv package is installed.
%pipCmd% show virtualenv >nul 2>&1
if %errorlevel% == 0 (
echo virtualenv already installed, proceeding
) else (
echo installing virtualenv with %pipCmd% ...
%pythonCmd% -m pip install --user virtualenv
REM %errorlevel% doesnt seem to return as expect from the above, so checking success via pip:
%pipCmd% show virtualenv >nul 2>&1
if %errorlevel% neq 0 (
echo pip install of virtualenv failed
exit /b 1
) else (
echo pip install of virtualenv succeeded
)
)
REM Create a python environment (stored in folder %folder%)
%pythonCmd% -m venv %folder%
if %errorlevel% neq 0 (
REM Virtual environment creation did not work:
echo Virtual environment creation did not work. Do you need to pip install virtualenv? >&2
exit /b 2
) else (
echo Virtual environment created in %folder%
)
REM enter the environment
call %folder%\Scripts\activate.bat
if %errorlevel% neq 0 (
echo Virtual environment unable to be activated
exit /b 3
) else (
echo Python environment started and activated.
echo Beginning pip installations for the environment
)
REM install jpype1 and numpy (does not matter if they are already installed)
%pipCmd% install jpype1
%pipCmd% install numpy
echo.
echo jpype1 and numpy installed - you have a functional installation.
echo.
echo Now trying scipy, matplotlib and jupyter, but they are optional...
echo.
%pipCmd% install scipy
%pipCmd% install matplotlib
%pipCmd% install jupyter
echo.
echo scipy, matplotlib and jupyter installed
echo.
echo.
echo In Powershell activate the environment via calling: %folder%\Scripts\Activate.ps1
echo Otherwise activate the environment via calling: %folder%\Scripts\activate.bat
deactivate

84
demos/python/create_env.sh Executable file
View File

@ -0,0 +1,84 @@
#!/bin/bash
##
## Java Information Dynamics Toolkit (JIDT)
## Copyright (C) 2022, 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/>.
##
# Create a python environment (stored in folder $folder) with jpype1, numpy and scipy installed
# Name of folder to use and python commands
folder=jpype_env
pythonCmd=python3
pipCmd=pip3
# First make sure that the virtualenv package is installed.
$pipCmd show virtualenv > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "virtualenv already installed, proceeding"
else
echo "installing virtualenv with $pipCmd ...".
# On ubuntu, one could also install via the main package manager, e.g. sudo apt-get install python3-venv (I think this takes care of the followng anyway, but am unsure)
$pythonCmd -m pip install --user virtualenv
if [ $? -ne 0 ]; then
echo "pip install of virtualenv failed"
exit 1
else
echo "pip install of virtualenv succeeded"
fi
fi
# Create a python environment (stored in folder $folder)
$pythonCmd -m venv $folder
if [ $? -ne 0 ]; then
# Virtual environment creation did not work:
echo "Virtual environment creation did not work." >&2
echo "If you are on ubuntu you should now run: sudo apt-get install python3-venv" >&2
echo "Then run this script again" >&2
exit 2
else
echo "Virtual environment created in $folder"
fi
# enter the environment
source $folder/bin/activate
if [ $? -ne 0 ]; then
echo "Virtual environment unable to be activated" >&2
exit 3
else
echo "Python environment started and activated."
echo "Beginning pip installations for the environment"
fi
# install jpype1 and numpy (does not matter if they are already installed)
$pipCmd install jpype1
$pipCmd install numpy
echo
echo "Jpype1 and numpy installed - you have a functional installation."
echo
echo "Now trying scipy, matplotlib and jupyter, but they are optional..."
echo
$pipCmd install scipy
$pipCmd install matplotlib
$pipCmd install jupyter
echo
echo "Scipy, matplotlib and jupyter installed"
echo
deactivate

11
demos/python/example1TeBinaryData.py Executable file → Normal file
View File

@ -23,9 +23,12 @@
import jpype
import random
import numpy
import os
# Change location of jar to match yours:
jarLocation = "../../infodynamics.jar"
# Change location of jar to match yours (we assume script is called from demos/python):
jarLocation = os.path.join(os.getcwd(), "..", "..", "infodynamics.jar");
if (not(os.path.isfile(jarLocation))):
exit("infodynamics.jar not found (expected at " + os.path.abspath(jarLocation) + ") - are you running from demos/python?")
# Start the JVM (add the "-Xmx" option with say 1024M if you get crashes due to not enough memory space)
jpype.startJVM(jpype.getDefaultJVMPath(), "-ea", "-Djava.class.path=" + jarLocation)
@ -49,8 +52,8 @@ print("For random source, result should be close to 0 bits: %.4f" % teCalc.compu
# Next, demonstrate how to do this with a numpy array
teCalc.initialise()
# Create the numpy arrays:
sourceNumpy = numpy.array(sourceArray, dtype=numpy.int)
destNumpy = numpy.array(destArray, dtype=numpy.int)
sourceNumpy = numpy.array(sourceArray, dtype=int)
destNumpy = numpy.array(destArray, dtype=int)
# The above can be passed straight through to JIDT in python 2:
# teCalc.addObservations(sourceNumpy, destNumpy)
# But you need to do this in python 3:

View File

@ -24,9 +24,12 @@
from jpype import *
import random
import os
# Change location of jar to match yours:
jarLocation = "../../infodynamics.jar"
# Change location of jar to match yours (we assume script is called from demos/python):
jarLocation = os.path.join(os.getcwd(), "..", "..", "infodynamics.jar");
if (not(os.path.isfile(jarLocation))):
exit("infodynamics.jar not found (expected at " + os.path.abspath(jarLocation) + ") - are you running from demos/python?")
# 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)

View File

@ -23,9 +23,12 @@
from jpype import *
import random
import math
import os
# Change location of jar to match yours:
jarLocation = "../../infodynamics.jar"
# Change location of jar to match yours (we assume script is called from demos/python):
jarLocation = os.path.join(os.getcwd(), "..", "..", "infodynamics.jar");
if (not(os.path.isfile(jarLocation))):
exit("infodynamics.jar not found (expected at " + os.path.abspath(jarLocation) + ") - are you running from demos/python?")
# 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)

View File

@ -23,9 +23,12 @@
from jpype import *
import random
import math
import os
# Change location of jar to match yours:
jarLocation = "../../infodynamics.jar"
# Change location of jar to match yours (we assume script is called from demos/python):
jarLocation = os.path.join(os.getcwd(), "..", "..", "infodynamics.jar");
if (not(os.path.isfile(jarLocation))):
exit("infodynamics.jar not found (expected at " + os.path.abspath(jarLocation) + ") - are you running from demos/python?")
# 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)

View File

@ -23,9 +23,12 @@
from jpype import *
import random
from operator import xor
import os
# Change location of jar to match yours:
jarLocation = "../../infodynamics.jar"
# Change location of jar to match yours (we assume script is called from demos/python):
jarLocation = os.path.join(os.getcwd(), "..", "..", "infodynamics.jar");
if (not(os.path.isfile(jarLocation))):
exit("infodynamics.jar not found (expected at " + os.path.abspath(jarLocation) + ") - are you running from demos/python?")
# 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)

View File

@ -31,9 +31,12 @@ import random
import string
import numpy
import readFloatsFile
import os
# Change location of jar to match yours:
jarLocation = "../../infodynamics.jar"
# Change location of jar to match yours (we assume script is called from demos/python):
jarLocation = os.path.join(os.getcwd(), "..", "..", "infodynamics.jar");
if (not(os.path.isfile(jarLocation))):
exit("infodynamics.jar not found (expected at " + os.path.abspath(jarLocation) + ") - are you running from demos/python?")
# 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)
@ -89,7 +92,7 @@ miCalc = miCalcClass()
# a. Initialise the calculator for a univariate calculation:
miCalc.initialise(1, 1)
# b. Supply the observations to compute the PDFs from:
miCalc.setObservations(univariateSeries1, univariateSeries2)
miCalc.setObservations(JArray(JDouble, 1)(univariateSeries1.tolist()), JArray(JDouble, 1)(univariateSeries2.tolist()))
# c. Make the MI calculation:
miUnivariateValue = miCalc.computeAverageLocalOfObservations()
@ -100,7 +103,7 @@ miUnivariateValue = miCalc.computeAverageLocalOfObservations()
# to use the required number of dimensions for each variable:
miCalc.initialise(len(jointVariable1Columns), len(jointVariable2Columns))
# b. Supply the observations to compute the PDFs from:
miCalc.setObservations(jointVariable1, jointVariable2)
miCalc.setObservations(JArray(JDouble, 2)(jointVariable1.tolist()), JArray(JDouble, 2)(jointVariable2.tolist()))
# c. Make the MI calculation:
miJointValue = miCalc.computeAverageLocalOfObservations()

View File

@ -24,9 +24,12 @@
from jpype import *
import random
import math
import os
# Change location of jar to match yours:
jarLocation = "../../infodynamics.jar"
# Change location of jar to match yours (we assume script is called from demos/python):
jarLocation = os.path.join(os.getcwd(), "..", "..", "infodynamics.jar");
if (not(os.path.isfile(jarLocation))):
exit("infodynamics.jar not found (expected at " + os.path.abspath(jarLocation) + ") - are you running from demos/python?")
# 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)

View File

@ -21,15 +21,17 @@
# Transfer entropy (TE) calculation on continuous-valued data using the Kraskov-estimator TE calculator,
# with automatic selection of embedding parameters
from jpype import *
import random
import math
import numpy
import readFloatsFile
import os
# Change location of jar to match yours:
jarLocation = "../../infodynamics.jar"
# Change location of jar to match yours (we assume script is called from demos/python):
jarLocation = os.path.join(os.getcwd(), "..", "..", "infodynamics.jar");
if (not(os.path.isfile(jarLocation))):
exit("infodynamics.jar not found (expected at " + os.path.abspath(jarLocation) + ") - are you running from demos/python?")
# 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)

42
demos/python/start_env.sh Executable file
View File

@ -0,0 +1,42 @@
#!/bin/bash
##
## Java Information Dynamics Toolkit (JIDT)
## Copyright (C) 2022, 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/>.
##
# Start the python environment (stored in folder $folder) with jpype1, numpy and others installed
# Name of folder to use and python commands
folder=jpype_env
# enter the environment
source $folder/bin/activate
if [ $? -ne 0 ]; then
echo "Virtual environment unable to be activated" >&2
# Try return first in case this script was sourced.
return 3 2>/dev/null
exit 3
else
echo "Python environment from $folder started and activated."
fi
echo
echo "Make sure you called this script as: source start_env.sh"
echo
echo "If you called it like that, you will have your python environment activated."
echo "If you just called ./start_env.sh go back and run again as above"
echo

View File

@ -0,0 +1,41 @@
#!/bin/bash
##
## Java Information Dynamics Toolkit (JIDT)
## Copyright (C) 2022, 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/>.
##
# Start the python environment (stored in folder $folder) with jpype1, numpy and others installed
# and then launch jupyter
# Name of folder to use and python commands
folder=jpype_env
# enter the environment
source $folder/bin/activate
if [[ "$VIRTUAL_ENV" != "" ]]
then
echo "Started virtual environment, now starting jupyter ..."
else
echo "Virtual environment not started, exiting"
# Try return first in case this script was sourced.
return 1 2>/dev/null
exit 1
fi
cd ../..
jupyter notebook

View File

@ -0,0 +1,45 @@
##
## Java Information Dynamics Toolkit (JIDT)
## Copyright (C) 2020, 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/>.
##
def writeFloatsFile(filename, array):
"Write a 2D array of floats to a given file"
with open(filename, "w") as f:
# Space separate numbers, one time step per line, each column is a variable
for item in array:
# write all items
if iterable(item):
# Assume this item is a row with several columns of data
first = True;
for subitem in item:
if (not(first)):
f.write(" ");
f.write("%f" % subitem)
first = False;
else:
f.write("%f" % item)
f.write("\n")
f.close()
def iterable(a):
try:
iter(a)
except Exception:
return False
else:
return True

View File

@ -0,0 +1,45 @@
##
## Java Information Dynamics Toolkit (JIDT)
## Copyright (C) 2020, 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/>.
##
def writeIntsFile(filename, array):
"Write a 2D array of ints to a given file"
with open(filename, "w") as f:
# Space separate numbers, one time step per line, each column is a variable
for item in array:
# write all items
if iterable(item):
# Assume this item is a row with several columns of data
first = True;
for subitem in item:
if (not(first)):
f.write(" ");
f.write("%d" % subitem)
first = False;
else:
f.write("%d" % item)
f.write("\n")
f.close()
def iterable(a):
try:
iter(a)
except Exception:
return False
else:
return True

BIN
demos/r/README-R_Demos.pdf Executable file → Normal file

Binary file not shown.

Binary file not shown.

View File

@ -60,5 +60,6 @@ nullDist <- .jcall(teCalc,"Linfodynamics/utils/EmpiricalMeasurementDistribution;
"computeSignificance", 100L)
cat("Null distribution for unrelated source and destination",
"(i.e. the bias) has mean", .jcall(nullDist, "D", "getMeanOfDistribution"),
"bits and standard deviation", .jcall(nullDist, "D", "getStdOfDistribution"), "\n")
"bits and standard deviation", .jcall(nullDist, "D", "getStdOfDistribution"),
", while the above measurement is beaten by a proportion of", nullDist$pValue, "of the null distribution\n")

View File

@ -28,6 +28,7 @@ import infodynamics.utils.EmpiricalNullDistributionComputer;
import infodynamics.utils.MatrixUtils;
import javax.swing.BorderFactory;
import javax.swing.DefaultCellEditor;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
@ -49,6 +50,7 @@ import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
@ -108,11 +110,13 @@ public abstract class AutoAnalyser extends JFrame
protected String[] discreteProperties; // Children to initialise
protected String[] discretePropertyDefaultValues; // Children to initialise
protected String[] discretePropertyDescriptions; // Children to initialise
protected String[][] discretePropertyValueChoices; // Children to initialise
// Common property names for all continuous calculators:
protected String[] commonContPropertyNames;
protected String[] commonContPropertiesFieldNames;
protected String[] commonContPropertyDescriptions;
protected String[][] commonContPropertyValueChoices;
// Children can define properties for specific continuous
// calculators
@ -179,6 +183,8 @@ public abstract class AutoAnalyser extends JFrame
protected int numPermutationsToCheck = 100;
// Table for the properties
protected JTable propertiesTable;
// Default editor for the property values
protected TableCellEditor propertiesDefaultEditor;
// Table model (local class) for the table
protected PropertiesTableModel propertiesTableModel;
// Names of the properties
@ -187,6 +193,8 @@ public abstract class AutoAnalyser extends JFrame
protected Vector<String> propertyFieldNames;
// Descriptions of the fields for the properties
protected Vector<String> propertyDescriptions;
// Lists of drop-down options for the properties
protected Vector<String[]> propertyValueChoices;
// Values of the properties
protected HashMap<String,String> propertyValues;
// CheckBox for "Compute result?"
@ -213,7 +221,7 @@ public abstract class AutoAnalyser extends JFrame
protected String pathToAutoAnalyserDir = "";
// Main JIDT git/distribution folder, inferred from pathToAutoAnalyserDir
protected String jidtFolder = "";
public class TextAreaWithImage extends JTextArea {
/**
@ -294,7 +302,7 @@ public abstract class AutoAnalyser extends JFrame
Image watermarkImage = (new ImageIcon(pathToAutoAnalyserDir + "JIDT-logo-watermark.png")).getImage();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1100,670);
setSize(1100,680);
setTitle(appletTitle);
// Centre in the middle of the screen
setLocationRelativeTo(null);
@ -366,13 +374,17 @@ public abstract class AutoAnalyser extends JFrame
putCalcPropertiesInTable();
propertiesTableModel = new PropertiesTableModel();
propertiesTable = new TableWithToolTip(propertiesTableModel);
// Get the default editor for the properties values:
propertiesDefaultEditor = propertiesTable.getDefaultEditor(
propertiesTable.getColumnClass(1));
System.out.println("Default properties editor is " + propertiesDefaultEditor.getClass().getName());
// Make sure any properties are saved when the compute button is clicked
propertiesTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
Font headerFont = propertiesTable.getTableHeader().getFont();
propertiesTable.getTableHeader().setFont(headerFont.deriveFont(Font.BOLD));
TableColumn valueColumn = propertiesTable.getColumn("Property value");
valueColumn.setMinWidth(130);
valueColumn.setMaxWidth(130);
valueColumn.setMinWidth(170);
valueColumn.setMaxWidth(170);
JScrollPane propsTableScrollPane = new JScrollPane(propertiesTable);
// Set up for ~18 rows maximum (the +6 is exact to fit all props
// for Kraskov TE in without scrollbar)
@ -383,7 +395,7 @@ public abstract class AutoAnalyser extends JFrame
propsTableScrollPane.setMinimumSize(
new Dimension(d.width,rowHeight*17+6));
System.out.println("Row height was " + rowHeight);
// Checkbox for compute result
computeResultCheckBox = new JCheckBox("Compute result?");
computeResultCheckBox.setToolTipText("Compute result or only generate code?");
@ -418,7 +430,7 @@ public abstract class AutoAnalyser extends JFrame
javaAreaScrollPane.setHorizontalScrollBarPolicy(
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
int codeTextAreaWidth = 560;
int codeTextAreaHeight = 480;
int codeTextAreaHeight = 530;
Dimension codeTextAreaDimension =
new Dimension(codeTextAreaWidth, codeTextAreaHeight);
javaAreaScrollPane.setPreferredSize(codeTextAreaDimension);
@ -653,8 +665,8 @@ public abstract class AutoAnalyser extends JFrame
}
protected void loadData(boolean isInts) {
ArrayFileReader afr = new ArrayFileReader(dataFile);
try {
ArrayFileReader afr = new ArrayFileReader(dataFile);
if (isInts) {
dataDiscrete = afr.getInt2DMatrix();
dataRows = dataDiscrete.length;
@ -716,33 +728,35 @@ public abstract class AutoAnalyser extends JFrame
int[] singleCalcColumns = new int[numVariables];
Vector<int[]> variableCombinations = new Vector<int[]>();
if (computeResultCheckBox.isSelected()) {
// Only need variableCombinations filled out if we're computing
try {
try {
if (!allCombosCheckBox.isSelected()) {
// we're doing a single combination
for (int i = 0; i < numVariables; i++) {
singleCalcColumns[i] = Integer.parseInt(variableColTextFields[i].getText());
if ((singleCalcColumns[i] < 0) || (singleCalcColumns[i] >= dataColumns)) {
JOptionPane.showMessageDialog(this,
String.format("%s column must be between 0 and %d for this data set",
variableColNumLabels[i], dataColumns-1));
resultsLabel.setText(" ");
return;
}
}
}
if (computeResultCheckBox.isSelected()) {
// Only need variableCombinations filled out if we're computing
if (allCombosCheckBox.isSelected()) {
// We're doing all combinations
fillOutAllCombinations(variableCombinations);
} else {
// we're doing a single combination
for (int i = 0; i < numVariables; i++) {
singleCalcColumns[i] = Integer.parseInt(variableColTextFields[i].getText());
if ((singleCalcColumns[i] < 0) || (singleCalcColumns[i] >= dataColumns)) {
JOptionPane.showMessageDialog(this,
String.format("%s column must be between 0 and %d for this data set",
variableColNumLabels[i], dataColumns-1));
resultsLabel.setText(" ");
return;
}
}
variableCombinations.add(singleCalcColumns);
}
} catch (Exception e) {
// Catches number format exception, and column number out of bounds
JOptionPane.showMessageDialog(this,
e.getMessage());
resultsLabel.setText("Cannot parse a column number from input: " + e.getMessage());
return;
}
} catch (Exception e) {
// Catches number format exception, and column number out of bounds
JOptionPane.showMessageDialog(this,
e.getMessage());
resultsLabel.setText("Cannot parse a column number from input: " + e.getMessage());
return;
}
// Generate headers:
@ -771,11 +785,11 @@ public abstract class AutoAnalyser extends JFrame
String jarLocation, pythonDemosLocation, matlabDemosLocation;
try {
File jarLocationFile = new File(jidtFolder + "infodynamics.jar");
jarLocation = jarLocationFile.getCanonicalPath();
jarLocation = jarLocationFile.getCanonicalPath().replace("\\", "\\\\");
File pythonDemosLocationFile = new File(pathToAutoAnalyserDir + "../python");
pythonDemosLocation = pythonDemosLocationFile.getCanonicalPath();
pythonDemosLocation = pythonDemosLocationFile.getCanonicalPath().replace("\\", "\\\\");
File matlabDemosLocationFile = new File(pathToAutoAnalyserDir + "../octave");
matlabDemosLocation = matlabDemosLocationFile.getCanonicalPath();
matlabDemosLocation = matlabDemosLocationFile.getCanonicalPath().replace("\\", "\\\\");
} catch (IOException ioex) {
JOptionPane.showMessageDialog(this,
ioex.getMessage());
@ -786,6 +800,7 @@ public abstract class AutoAnalyser extends JFrame
StringBuffer pythonCode = new StringBuffer();
pythonCode.append("from jpype import *\n");
pythonCode.append("import numpy\n");
pythonCode.append("import sys\n");
pythonCode.append("# Our python data file readers are a bit of a hack, python users will do better on this:\n");
pythonCode.append("sys.path.append(\"" + pythonDemosLocation + "\")\n");
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE)) {
@ -793,10 +808,11 @@ public abstract class AutoAnalyser extends JFrame
} else {
pythonCode.append("import readFloatsFile\n\n");
}
pythonCode.append("# Add JIDT jar library to the path\n");
pythonCode.append("jarLocation = \"" + jarLocation + "\"\n");
pythonCode.append("# Start the JVM (add the \"-Xmx\" option with say 1024M if you get crashes due to not enough memory space)\n");
pythonCode.append("startJVM(getDefaultJVMPath(), \"-ea\", \"-Djava.class.path=\" + jarLocation)\n\n");
pythonCode.append("if (not isJVMStarted()):\n");
pythonCode.append(" # Add JIDT jar library to the path\n");
pythonCode.append(" jarLocation = \"" + jarLocation + "\"\n");
pythonCode.append(" # Start the JVM (add the \"-Xmx\" option with say 1024M if you get crashes due to not enough memory space)\n");
pythonCode.append(" startJVM(getDefaultJVMPath(), \"-ea\", \"-Djava.class.path=\" + jarLocation, convertStrings=True)\n\n");
// 3. Matlab:
StringBuffer matlabCode = new StringBuffer();
matlabCode.append("% Add JIDT jar library to the path, and disable warnings that it's already there:\n");
@ -902,9 +918,9 @@ public abstract class AutoAnalyser extends JFrame
// 2. Python
pythonCode.append("# " + loadDataComment);
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE)) {
pythonCode.append("dataRaw = readIntsFile.readIntsFile(\"" + dataFile.getAbsolutePath() + "\")\n");
pythonCode.append("dataRaw = readIntsFile.readIntsFile(\"" + filenameAsEscapedString + "\")\n");
} else {
pythonCode.append("dataRaw = readFloatsFile.readFloatsFile(\"" + dataFile.getAbsolutePath() + "\")\n");
pythonCode.append("dataRaw = readFloatsFile.readFloatsFile(\"" + filenameAsEscapedString + "\")\n");
}
pythonCode.append("# As numpy array:\n");
pythonCode.append("data = numpy.array(dataRaw)\n");
@ -922,15 +938,15 @@ public abstract class AutoAnalyser extends JFrame
}
} else {
for (int i=0; i < numVariables; i++) {
pythonCode.append(variableColNumLabels[i].toLowerCase() + " = data[:," +
singleCalcColumns[i] + "]\n");
pythonCode.append(variableColNumLabels[i].toLowerCase() + " = JArray(JDouble, 1)(data[:," +
singleCalcColumns[i] + "].tolist())\n");
}
}
pythonCode.append("\n");
}
// 3. Matlab
matlabCode.append("% " + loadDataComment);
matlabCode.append("data = load('" + dataFile.getAbsolutePath() + "');\n");
matlabCode.append("data = load('" + filenameAsEscapedString + "');\n");
if (! allCombosCheckBox.isSelected()) {
matlabCode.append("% Column indices start from 1 in Matlab:\n");
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE)) {
@ -1112,13 +1128,14 @@ public abstract class AutoAnalyser extends JFrame
columnVariables[i] + "].tolist()), " + propertyValues.get(DISCRETE_PROPNAME_BASE) + ")\n");
}
} else {
// Continuous data
for (int i = 0; i < numVariables; i++) {
javaCode.append(javaPrefix + "double[] " + variableColNumLabels[i].toLowerCase() +
" = MatrixUtils.selectColumn(data, " + columnVariables[i] + ");\n");
matlabCode.append(matlabPrefix + variableColNumLabels[i].toLowerCase() +
" = octaveToJavaDoubleArray(data(:, " + columnVariables[i] + "));\n");
pythonCode.append(pythonPrefix + variableColNumLabels[i].toLowerCase() +
" = data[:, " + columnVariables[i] + "]\n");
" = JArray(JDouble, 1)(data[:, " + columnVariables[i] + "].tolist())\n");
}
}
javaCode.append("\n");
@ -1160,7 +1177,7 @@ public abstract class AutoAnalyser extends JFrame
javaCode.append(javaPrefix + "calc." + setObservationsMethod + "(" + methodArguments + ");\n");
// 2. Python
pythonCode.append(pythonPrefix + "# " + supplyDataComment);
pythonCode.append(pythonPrefix + "calc." + setObservationsMethod + "(" + methodArguments + ")\n");
pythonCode.append(pythonPrefix + "calc." + setObservationsMethod + pythonSetObsSuffix() + "(" + methodArguments + ")\n");
// 3. Matlab
matlabCode.append(matlabPrefix + "% " + supplyDataComment);
matlabCode.append(matlabPrefix + "calc." + setObservationsMethod + "(" + methodArguments + ");\n");
@ -1224,7 +1241,7 @@ public abstract class AutoAnalyser extends JFrame
extraFormatTerms + "result" + statSigFormatTerms + ");\n");
// 2. Python
pythonCode.append("\n" + pythonPrefix + "print(\"" + resultsPrefixString +
"%.4f " + units + resultsSuffixString + "\" %\n " + pythonPrefix + "(" +
"%.4f " + units + resultsSuffixString + "\" %\\\n " + pythonPrefix + "(" +
extraFormatTerms + "result" + statSigFormatTerms + "))\n");
// 3. Matlab
matlabCode.append("\n" + matlabPrefix + "fprintf('" + resultsPrefixString +
@ -1375,7 +1392,7 @@ public abstract class AutoAnalyser extends JFrame
System.out.println(resultsText);
}
if ((allCombosCheckBox.isSelected()) &&
if ((!allCombosCheckBox.isSelected()) &&
!(selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE) ||
(selectedCalcType.equalsIgnoreCase(CALC_TYPE_BINNED)))) {
// Read the current property values back out (in case of
@ -1503,7 +1520,15 @@ public abstract class AutoAnalyser extends JFrame
InfoMeasureCalculatorContinuous calcContinuous,
int[] columnCombo) throws Exception;
/**
* Method to return any suffix if required on the set/addObservations method for python calls
*
* @return
*/
protected String pythonSetObsSuffix() {
return "";
}
/**
* Extends JTable to add ToolTipText to the property names
*
@ -1528,9 +1553,22 @@ public abstract class AutoAnalyser extends JFrame
if (vColIndex == 0) {
JComponent jc = (JComponent)c;
try {
jc.setToolTipText("<html>" + propertyFieldNames.get(rowIndex) + ": " + propertyDescriptions.get(rowIndex) + "</html>");
String toolTipText;
String selectedCalcType = (String)
calcTypeComboBox.getSelectedItem();
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE) ||
selectedCalcType.equalsIgnoreCase(CALC_TYPE_BINNED)) {
toolTipText = "<html>" + propertyNames.get(rowIndex) + ": " +
propertyDescriptions.get(rowIndex) + "</html>";
} else {
toolTipText = "<html>" + propertyFieldNames.get(rowIndex) + ": " +
propertyDescriptions.get(rowIndex) + "</html>";
}
jc.setToolTipText(toolTipText);
} catch (ArrayIndexOutOfBoundsException aioobe) {
// Catch if the row number was outside our array of descriptions (e.g. empty row)
System.out.println("prepareRenderer: Row number " + rowIndex +
" was outside our array of names/fieldnames/descriptions");
}
}
}
@ -1556,6 +1594,70 @@ public abstract class AutoAnalyser extends JFrame
}
}
*/
/**
* Use this method to set combo box options for editing cells
*/
@Override
public TableCellEditor getCellEditor(int row, int column) {
if ((propertyValueChoices.get(row) != null) && (column == 1)) {
// We need to construct a combo box for the selection for this property:
try {
JComboBox<String> paramChoiceComboBox = new JComboBox<String>();
// Set font to not bold and one size less than the default (to fit better)
Font font = paramChoiceComboBox.getFont();
paramChoiceComboBox.setFont(font.deriveFont(Font.PLAIN, font.getSize()-1));
String[] choices = propertyValueChoices.get(row);
for (int c = 0; c < choices.length; c++) {
paramChoiceComboBox.addItem(choices[c]);
}
return new DefaultCellEditor(paramChoiceComboBox);
} catch (Exception e) {
e.printStackTrace();
// But now allow this to be handled by the default cell editor
}
}
// I think the following would do the default behaviour:
// return this.getDefaultEditor(this.getColumnClass(column));
// however it should be safer to just allow the parent to handle:
return super.getCellEditor(row, column);
}
/**
* This method allows us to keep a combo box visible when
* the property value is no longer selected.
* Adapted from answer at https://stackoverflow.com/questions/30744524/how-to-make-the-jcombobox-dropdown-always-visible-in-a-jtable
*/
@Override
public TableCellRenderer getCellRenderer(int row, int column) {
if ((propertyValueChoices.get(row) != null) && (column == 1)) {
try {
return new TableCellRenderer() {
JComboBox<String> box = new JComboBox<String>();
int defaultFontSize = box.getFont().getSize();
@Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
// Set font to not bold and one size less than the default (to fit better)
Font font = box.getFont();
box.setFont(font.deriveFont(Font.PLAIN, defaultFontSize-1));
// Now empty all items out and just put the value we currently have.
// (This is only for displaying, the editor will override with available values if
// user wants to edit).
box.removeAllItems();
box.addItem(value.toString());
return box;
}
};
} catch (Exception e) {
e.printStackTrace();
// But now allow this to be handled by the default cell renderer
}
}
return super.getCellRenderer(row, column);
}
}
protected class PropertiesTableModel extends AbstractTableModel {
@ -1643,6 +1745,8 @@ public abstract class AutoAnalyser extends JFrame
calcProperties.classSpecificPropertiesFieldNames;
String[] classSpecificPropertyDescriptions =
calcProperties.classSpecificPropertyDescriptions;
String[][] classSpecificPropertyValueChoices =
calcProperties.classSpecificPropertyValueChoices;
calcClass = calcProperties.calcClass;
Object calc = calcProperties.calc;
@ -1650,6 +1754,7 @@ public abstract class AutoAnalyser extends JFrame
propertyNames = new Vector<String>();
propertyFieldNames = new Vector<String>();
propertyDescriptions = new Vector<String>();
propertyValueChoices = new Vector<String[]>();
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE) ||
selectedCalcType.equalsIgnoreCase(CALC_TYPE_BINNED)) {
@ -1660,10 +1765,12 @@ public abstract class AutoAnalyser extends JFrame
for (String propName : discreteProperties) {
String propertyDescription = discretePropertyDescriptions[i];
String defaultPropertyValue = discretePropertyDefaultValues[i];
String[] propertyValueChoiceSet = discretePropertyValueChoices[i];
i++;
propertyNames.add(propName);
propertyDescriptions.add(propertyDescription);
propertyValues.put(propName, defaultPropertyValue);
propertyValueChoices.add(propertyValueChoiceSet);
System.out.println("Adding property name " + propName);
}
} else {
@ -1672,6 +1779,7 @@ public abstract class AutoAnalyser extends JFrame
for (String fieldName : commonContPropertiesFieldNames) {
String propName = commonContPropertyNames[i];
String propertyDescription = commonContPropertyDescriptions[i];
String[] propertyValueChoiceSet = commonContPropertyValueChoices[i];
i++;
System.out.println("Adding property name " +
abstractContinuousClass.getSimpleName() + "." + fieldName +
@ -1679,6 +1787,7 @@ public abstract class AutoAnalyser extends JFrame
propertyFieldNames.add(abstractContinuousClass.getSimpleName() + "." + fieldName);
propertyNames.add(propName);
propertyDescriptions.add(propertyDescription);
propertyValueChoices.add(propertyValueChoiceSet);
}
// Then for the specific estimator types
@ -1686,9 +1795,11 @@ public abstract class AutoAnalyser extends JFrame
for (String fieldName : classSpecificPropertiesFieldNames) {
String propName = classSpecificPropertyNames[i];
String propertyDescription = classSpecificPropertyDescriptions[i];
String[] propertyValueChoiceSet = classSpecificPropertyValueChoices[i];
i++;
propertyNames.add(propName);
propertyDescriptions.add(propertyDescription);
propertyValueChoices.add(propertyValueChoiceSet);
if (fieldName.contains(".")) {
System.out.println("Adding property name " + fieldName +
" = \"" + propName + "\"");
@ -1734,6 +1845,7 @@ public abstract class AutoAnalyser extends JFrame
String[] classSpecificPropertyNames;
String[] classSpecificPropertiesFieldNames;
String[] classSpecificPropertyDescriptions;
String[][] classSpecificPropertyValueChoices;
}
/**
@ -1756,6 +1868,7 @@ public abstract class AutoAnalyser extends JFrame
calcProperties.classSpecificPropertyNames = discreteProperties;
calcProperties.classSpecificPropertiesFieldNames = null; // Not used
calcProperties.classSpecificPropertyDescriptions = discretePropertyDescriptions;
calcProperties.classSpecificPropertyValueChoices = discretePropertyValueChoices;
// TODO Later can add binning method to the properties for
// binned calculator here.
return calcProperties;

View File

@ -19,9 +19,12 @@
package infodynamics.demos.autoanalysis;
import infodynamics.measures.continuous.ActiveInfoStorageCalculator;
import infodynamics.measures.continuous.ActiveInfoStorageCalculatorViaMutualInfo;
import infodynamics.measures.continuous.InfoMeasureCalculatorContinuous;
import infodynamics.measures.continuous.gaussian.ActiveInfoStorageCalculatorGaussian;
import infodynamics.measures.continuous.gaussian.MutualInfoCalculatorMultiVariateGaussian;
import infodynamics.measures.continuous.kernel.ActiveInfoStorageCalculatorKernel;
import infodynamics.measures.continuous.kernel.ActiveInfoStorageCalculatorMultiVariateKernel;
import infodynamics.measures.continuous.kernel.MutualInfoCalculatorMultiVariateKernel;
import infodynamics.measures.continuous.kraskov.ActiveInfoStorageCalculatorKraskov;
import infodynamics.measures.continuous.kraskov.MutualInfoCalculatorMultiVariateKraskov;
@ -55,12 +58,15 @@ public class AutoAnalyserAIS extends AutoAnalyser {
protected String[] gaussianProperties;
protected String[] gaussianPropertiesFieldNames;
protected String[] gaussianPropertyDescriptions;
protected String[][] gaussianPropertyValueChoices;
protected String[] kernelProperties;
protected String[] kernelPropertiesFieldNames;
protected String[] kernelPropertyDescriptions;
protected String[][] kernelPropertyValueChoices;
protected String[] kraskovProperties;
protected String[] kraskovPropertiesFieldNames;
protected String[] kraskovPropertyDescriptions;
protected String[][] kraskovPropertyValueChoices;
public AutoAnalyserAIS() {
super();
@ -106,39 +112,84 @@ public class AutoAnalyserAIS extends AutoAnalyser {
"Number of discrete states available for each variable (i.e. 2 for binary)",
"History embedding length (k_HISTORY)"
};
discretePropertyValueChoices = new String[][] {
null,
null
};
// Continuous:
abstractContinuousClass = ActiveInfoStorageCalculator.class;
// Common properties for all continuous calcs:
commonContPropertyNames = new String[] {
ActiveInfoStorageCalculator.K_PROP_NAME,
ActiveInfoStorageCalculator.TAU_PROP_NAME
ActiveInfoStorageCalculator.TAU_PROP_NAME,
ActiveInfoStorageCalculatorViaMutualInfo.PROP_AUTO_EMBED_METHOD,
ActiveInfoStorageCalculatorViaMutualInfo.PROP_K_SEARCH_MAX,
ActiveInfoStorageCalculatorViaMutualInfo.PROP_TAU_SEARCH_MAX,
};
commonContPropertiesFieldNames = new String[] {
"K_PROP_NAME",
"TAU_PROP_NAME"
"TAU_PROP_NAME",
"ActiveInfoStorageCalculatorViaMutualInfo.PROP_AUTO_EMBED_METHOD",
"ActiveInfoStorageCalculatorViaMutualInfo.PROP_K_SEARCH_MAX",
"ActiveInfoStorageCalculatorViaMutualInfo.PROP_TAU_SEARCH_MAX",
};
commonContPropertyDescriptions = new String[] {
"History embedding length (k_HISTORY)",
"History embedding delay (k_TAU)"
"History embedding delay (k_TAU)",
"Method to automatically determine embedding length (k_HISTORY)<br/> and delay (k_TAU) for " +
"the samples. Default is \"" + ActiveInfoStorageCalculatorKraskov.AUTO_EMBED_METHOD_NONE +
"\" meaning values are set manually; other values include: <br/> -- \"" + ActiveInfoStorageCalculatorKraskov.AUTO_EMBED_METHOD_RAGWITZ +
"\" for use of the Ragwitz criteria for both source and destination (searching up to \"" + ActiveInfoStorageCalculatorKraskov.PROP_K_SEARCH_MAX +
"\" and \"" + ActiveInfoStorageCalculatorKraskov.PROP_TAU_SEARCH_MAX + "\"); <br/> -- \"" + ActiveInfoStorageCalculatorKraskov.AUTO_EMBED_METHOD_MAX_CORR_AIS +
"\" for maximising the (bias corrected) Active Info Storage (searching up to \"" + ActiveInfoStorageCalculatorKraskov.PROP_K_SEARCH_MAX +
"\" and \"" + ActiveInfoStorageCalculatorKraskov.PROP_TAU_SEARCH_MAX + "\"); <br/>Use of values other than \"" + ActiveInfoStorageCalculatorKraskov.AUTO_EMBED_METHOD_NONE +
"\" leads to any previous settings for embedding lengths and delays to be overwritten after observations are supplied",
"Max. embedding length to search to <br/>if auto embedding (as determined by " + ActiveInfoStorageCalculatorKraskov.PROP_AUTO_EMBED_METHOD + ")",
"Max. embedding delay to search to <br/>if auto embedding (as determined by " + ActiveInfoStorageCalculatorKraskov.PROP_AUTO_EMBED_METHOD + ")",
};
commonContPropertyValueChoices = new String[][] {
null,
null,
{ActiveInfoStorageCalculatorViaMutualInfo.AUTO_EMBED_METHOD_NONE,
ActiveInfoStorageCalculatorViaMutualInfo.AUTO_EMBED_METHOD_RAGWITZ,
ActiveInfoStorageCalculatorViaMutualInfo.AUTO_EMBED_METHOD_MAX_CORR_AIS},
null,
null,
};
// Gaussian properties:
gaussianProperties = new String[] {
MutualInfoCalculatorMultiVariateGaussian.PROP_BIAS_CORRECTION,
ActiveInfoStorageCalculatorGaussian.PROP_MAX_CORR_AIS_NUM_SURROGATES
};
gaussianPropertiesFieldNames = new String[] {
"MutualInfoCalculatorMultiVariateGaussian.PROP_BIAS_CORRECTION",
"ActiveInfoStorageCalculatorGaussian.PROP_MAX_CORR_AIS_NUM_SURROGATES"
};
gaussianPropertyDescriptions = new String[] {
"Whether the analytically determined bias (as the mean of the<br/>" +
"surrogate distribution) will be subtracted from all" +
"calculated values. Default is false.",
"Number of surrogates to use in computing the bias correction<br/>if required for " +
ActiveInfoStorageCalculatorKraskov.AUTO_EMBED_METHOD_MAX_CORR_AIS + " auto-embedding method.<br/>" +
"(default is 0, meaning to use analytic method -- recommended)"
};
gaussianPropertyValueChoices = new String[][] {
{"true", "false"},
null
};
// Kernel:
kernelProperties = new String[] {
MutualInfoCalculatorMultiVariateKernel.KERNEL_WIDTH_PROP_NAME,
MutualInfoCalculatorMultiVariateKernel.DYN_CORR_EXCL_TIME_NAME,
MutualInfoCalculatorMultiVariateKernel.NORMALISE_PROP_NAME,
MutualInfoCalculatorMultiVariateKernel.NORMALISE_PROP_NAME,
ActiveInfoStorageCalculatorMultiVariateKernel.PROP_MAX_CORR_AIS_NUM_SURROGATES
};
kernelPropertiesFieldNames = new String[] {
"KERNEL_WIDTH_PROP_NAME",
"DYN_CORR_EXCL_TIME_NAME",
"NORMALISE_PROP_NAME"
"MutualInfoCalculatorMultiVariateKernel.KERNEL_WIDTH_PROP_NAME",
"MutualInfoCalculatorMultiVariateKernel.DYN_CORR_EXCL_TIME_NAME",
"MutualInfoCalculatorMultiVariateKernel.NORMALISE_PROP_NAME",
"ActiveInfoStorageCalculatorMultiVariateKernel.PROP_MAX_CORR_AIS_NUM_SURROGATES"
};
kernelPropertyDescriptions = new String[] {
"Kernel width to be used in the calculation. <br/>If the property " +
@ -147,7 +198,16 @@ public class AutoAnalyserAIS extends AutoAnalyser {
"otherwise it is an absolute value.",
"Dynamic correlation exclusion time or <br/>Theiler window (see Kantz and Schreiber); " +
"0 (default) means no dynamic exclusion window",
"(boolean) whether to normalise <br/>each incoming time-series to mean 0, standard deviation 1, or not (recommended)",
"(boolean) whether to normalise <br/>each incoming time-series to mean 0, standard deviation 1, or not (default true, recommended)",
"Number of surrogates to use in computing the bias correction<br/>if required for " +
ActiveInfoStorageCalculatorKraskov.AUTO_EMBED_METHOD_MAX_CORR_AIS + " auto-embedding method.<br/>" +
"(default is 20)"
};
kernelPropertyValueChoices = new String[][] {
null,
null,
{"true", "false"},
null
};
// KSG (Kraskov):
kraskovProperties = new String[] {
@ -157,9 +217,8 @@ public class AutoAnalyserAIS extends AutoAnalyser {
MutualInfoCalculatorMultiVariateKraskov.PROP_DYN_CORR_EXCL_TIME,
MutualInfoCalculatorMultiVariateKraskov.PROP_NORM_TYPE,
MutualInfoCalculatorMultiVariateKraskov.PROP_NUM_THREADS,
ActiveInfoStorageCalculatorKraskov.PROP_AUTO_EMBED_METHOD,
ActiveInfoStorageCalculatorKraskov.PROP_K_SEARCH_MAX,
ActiveInfoStorageCalculatorKraskov.PROP_TAU_SEARCH_MAX,
MutualInfoCalculatorMultiVariateKraskov.PROP_USE_GPU,
ActiveInfoStorageCalculatorKraskov.PROP_KRASKOV_ALG_NUM,
ActiveInfoStorageCalculatorKraskov.PROP_RAGWITZ_NUM_NNS,
};
kraskovPropertiesFieldNames = new String[] {
@ -169,10 +228,9 @@ public class AutoAnalyserAIS extends AutoAnalyser {
"MutualInfoCalculatorMultiVariateKraskov.PROP_DYN_CORR_EXCL_TIME",
"MutualInfoCalculatorMultiVariateKraskov.PROP_NORM_TYPE",
"MutualInfoCalculatorMultiVariateKraskov.PROP_NUM_THREADS",
"PROP_AUTO_EMBED_METHOD",
"PROP_K_SEARCH_MAX",
"PROP_TAU_SEARCH_MAX",
"PROP_RAGWITZ_NUM_NNS"
"MutualInfoCalculatorMultiVariateKraskov.PROP_USE_GPU",
"PROP_KRASKOV_ALG_NUM",
"PROP_RAGWITZ_NUM_NNS"
};
kraskovPropertyDescriptions = new String[] {
"(boolean) whether to normalise <br/>each incoming time-series to mean 0, standard deviation 1, or not (recommended)",
@ -186,18 +244,21 @@ public class AutoAnalyserAIS extends AutoAnalyser {
"\"MAX_NORM\" (default), otherwise \"EUCLIDEAN\" or \"EUCLIDEAN_SQUARED\" (both equivalent here)",
"Number of parallel threads to use <br/>in computation: an integer > 0 or \"USE_ALL\" " +
"(default, to indicate to use all available processors)",
"Method to automatically determine embedding length (k_HISTORY)<br/> and delay (k_TAU) for " +
"the samples. Default is \"" + ActiveInfoStorageCalculatorKraskov.AUTO_EMBED_METHOD_NONE +
"\" meaning values are set manually; other values include: <br/> -- \"" + ActiveInfoStorageCalculatorKraskov.AUTO_EMBED_METHOD_RAGWITZ +
"\" for use of the Ragwitz criteria for both source and destination (searching up to \"" + ActiveInfoStorageCalculatorKraskov.PROP_K_SEARCH_MAX +
"\" and \"" + ActiveInfoStorageCalculatorKraskov.PROP_TAU_SEARCH_MAX + "\"); <br/> -- \"" + ActiveInfoStorageCalculatorKraskov.AUTO_EMBED_METHOD_MAX_CORR_AIS +
"\" for maximising the (bias corrected) Active Info Storage (searching up to \"" + ActiveInfoStorageCalculatorKraskov.PROP_K_SEARCH_MAX +
"\" and \"" + ActiveInfoStorageCalculatorKraskov.PROP_TAU_SEARCH_MAX + "\"); <br/>Use of values other than \"" + ActiveInfoStorageCalculatorKraskov.AUTO_EMBED_METHOD_NONE +
"\" leads to any previous settings for embedding lengths and delays to be overwritten after observations are supplied",
"Max. embedding length to search to <br/>if auto embedding (as determined by " + ActiveInfoStorageCalculatorKraskov.PROP_AUTO_EMBED_METHOD + ")",
"Max. embedding delay to search to <br/>if auto embedding (as determined by " + ActiveInfoStorageCalculatorKraskov.PROP_AUTO_EMBED_METHOD + ")",
"Whether to enable the GPU module (number of threads then has no bearing); boolean, default false",
"Which KSG algorithm to use (1 or 2)",
"Number of k nearest neighbours for <br/>Ragwitz auto embedding (if used; defaults to match property \"k\")"
};
kraskovPropertyValueChoices = new String[][] {
{"true", "false"},
null,
null,
null,
{"MAX_NORM", "EUCLIDEAN", "EUCLIDEAN_SQUARED"},
null,
{"true", "false"},
{"1", "2"},
null,
};
}
@Override
@ -304,14 +365,17 @@ public class AutoAnalyserAIS extends AutoAnalyser {
calcProperties.classSpecificPropertyNames = gaussianProperties;
calcProperties.classSpecificPropertiesFieldNames = gaussianPropertiesFieldNames;
calcProperties.classSpecificPropertyDescriptions = gaussianPropertyDescriptions;
calcProperties.classSpecificPropertyValueChoices = gaussianPropertyValueChoices;
} else if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_KRASKOV)) {
calcProperties.classSpecificPropertyNames = kraskovProperties;
calcProperties.classSpecificPropertiesFieldNames = kraskovPropertiesFieldNames;
calcProperties.classSpecificPropertyDescriptions = kraskovPropertyDescriptions;
calcProperties.classSpecificPropertyValueChoices = kraskovPropertyValueChoices;
} else if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_KERNEL)) {
calcProperties.classSpecificPropertyNames = kernelProperties;
calcProperties.classSpecificPropertiesFieldNames = kernelPropertiesFieldNames;
calcProperties.classSpecificPropertyDescriptions = kernelPropertyDescriptions;
calcProperties.classSpecificPropertyValueChoices = kernelPropertyValueChoices;
} else {
calcProperties = null;
throw new Exception("No recognised calculator selected: " +

View File

@ -56,9 +56,11 @@ public class AutoAnalyserCMI extends AutoAnalyser
protected String[] gaussianProperties;
protected String[] gaussianPropertiesFieldNames;
protected String[] gaussianPropertyDescriptions;
protected String[][] gaussianPropertyValueChoices;
protected String[] kraskovProperties;
protected String[] kraskovPropertiesFieldNames;
protected String[] kraskovPropertyDescriptions;
protected String[][] kraskovPropertyValueChoices;
protected static final String CALC_TYPE_KRASKOV_ALG1 = CALC_TYPE_KRASKOV + " alg. 1";
protected static final String CALC_TYPE_KRASKOV_ALG2 = CALC_TYPE_KRASKOV + " alg. 2";
@ -107,6 +109,9 @@ public class AutoAnalyserCMI extends AutoAnalyser
"Number of discrete states available for each variable (i.e. 2 for binary).<br/>" +
"Can be set individually for each variable -- see code."
};
discretePropertyValueChoices = new String[][] {
null
};
// Continuous:
abstractContinuousClass = ConditionalMutualInfoCalculatorMultiVariate.class;
@ -120,12 +125,23 @@ public class AutoAnalyserCMI extends AutoAnalyser
commonContPropertyDescriptions = new String[] {
// None
};
commonContPropertyValueChoices = new String[][] {
// None
};
// Gaussian properties:
gaussianProperties = new String[] {
ConditionalMutualInfoCalculatorMultiVariateGaussian.PROP_BIAS_CORRECTION,
};
gaussianPropertiesFieldNames = new String[] {
"PROP_BIAS_CORRECTION"
};
gaussianPropertyDescriptions = new String[] {
"Whether the analytically determined bias (as the mean of the<br/>" +
"surrogate distribution) will be subtracted from all" +
"calculated values. Default is false."
};
gaussianPropertyValueChoices = new String[][] {
{"true", "false"}
};
// KSG (Kraskov):
kraskovProperties = new String[] {
@ -135,6 +151,7 @@ public class AutoAnalyserCMI extends AutoAnalyser
ConditionalMutualInfoCalculatorMultiVariateKraskov.PROP_DYN_CORR_EXCL_TIME,
ConditionalMutualInfoCalculatorMultiVariateKraskov.PROP_NORM_TYPE,
ConditionalMutualInfoCalculatorMultiVariateKraskov.PROP_NUM_THREADS,
ConditionalMutualInfoCalculatorMultiVariateKraskov.PROP_USE_GPU,
};
kraskovPropertiesFieldNames = new String[] {
"ConditionalMutualInfoMultiVariateCommon.PROP_NORMALISE",
@ -143,6 +160,7 @@ public class AutoAnalyserCMI extends AutoAnalyser
"ConditionalMutualInfoCalculatorMultiVariateKraskov.PROP_DYN_CORR_EXCL_TIME",
"ConditionalMutualInfoCalculatorMultiVariateKraskov.PROP_NORM_TYPE",
"ConditionalMutualInfoCalculatorMultiVariateKraskov.PROP_NUM_THREADS",
"ConditionalMutualInfoCalculatorMultiVariateKraskov.PROP_USE_GPU"
};
kraskovPropertyDescriptions = new String[] {
"(boolean) whether to normalise <br/>each incoming time-series to mean 0, standard deviation 1, or not (recommended)",
@ -156,8 +174,17 @@ public class AutoAnalyserCMI extends AutoAnalyser
"\"MAX_NORM\" (default), otherwise \"EUCLIDEAN\" or \"EUCLIDEAN_SQUARED\" (both equivalent here)",
"Number of parallel threads to use <br/>in computation: an integer > 0 or \"USE_ALL\" " +
"(default, to indicate to use all available processors)",
"Whether to enable the GPU module (number of threads then has no bearing); boolean, default false"
};
kraskovPropertyValueChoices = new String[][] {
{"true", "false"},
null,
null,
null,
{"MAX_NORM", "EUCLIDEAN", "EUCLIDEAN_SQUARED"},
null,
{"true", "false"}
};
}
@Override
@ -310,11 +337,13 @@ public class AutoAnalyserCMI extends AutoAnalyser
calcProperties.classSpecificPropertyNames = gaussianProperties;
calcProperties.classSpecificPropertiesFieldNames = gaussianPropertiesFieldNames;
calcProperties.classSpecificPropertyDescriptions = gaussianPropertyDescriptions;
calcProperties.classSpecificPropertyValueChoices = gaussianPropertyValueChoices;
} else if (selectedCalcType.startsWith(CALC_TYPE_KRASKOV)) {
// The if statement will work for both MI Kraskov calculators
calcProperties.classSpecificPropertyNames = kraskovProperties;
calcProperties.classSpecificPropertiesFieldNames = kraskovPropertiesFieldNames;
calcProperties.classSpecificPropertyDescriptions = kraskovPropertyDescriptions;
calcProperties.classSpecificPropertyValueChoices = kraskovPropertyValueChoices;
} else {
calcProperties = null;
throw new Exception("No recognised calculator selected: " +
@ -363,6 +392,21 @@ public class AutoAnalyserCMI extends AutoAnalyser
base + ", " + base + ", " + base);
}
@Override
protected String pythonSetObsSuffix() {
String selectedCalcType = (String)
calcTypeComboBox.getSelectedItem();
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE) ||
selectedCalcType.equalsIgnoreCase(CALC_TYPE_BINNED)) {
return "";
} else {
// For the moment we could direct all calls to the 1D arrays version,
// but it is working fine with JPype 0.7; later
// when we have 2D inputs we should dynamically detect that and return "2D"
return "";
}
}
/**
* @param args
*/

View File

@ -21,6 +21,7 @@ package infodynamics.demos.autoanalysis;
import infodynamics.measures.continuous.ConditionalMutualInfoMultiVariateCommon;
import infodynamics.measures.continuous.ConditionalTransferEntropyCalculator;
import infodynamics.measures.continuous.InfoMeasureCalculatorContinuous;
import infodynamics.measures.continuous.gaussian.ConditionalMutualInfoCalculatorMultiVariateGaussian;
import infodynamics.measures.continuous.gaussian.ConditionalTransferEntropyCalculatorGaussian;
import infodynamics.measures.continuous.kraskov.ConditionalMutualInfoCalculatorMultiVariateKraskov;
import infodynamics.measures.continuous.kraskov.ConditionalTransferEntropyCalculatorKraskov;
@ -57,9 +58,11 @@ public class AutoAnalyserCTE extends AutoAnalyser
protected String[] gaussianProperties;
protected String[] gaussianPropertiesFieldNames;
protected String[] gaussianPropertyDescriptions;
protected String[][] gaussianPropertyValueChoices;
protected String[] kraskovProperties;
protected String[] kraskovPropertiesFieldNames;
protected String[] kraskovPropertyDescriptions;
protected String[][] kraskovPropertyValueChoices;
public AutoAnalyserCTE() {
super();
@ -108,6 +111,10 @@ public class AutoAnalyserCTE extends AutoAnalyser
"Can be set individually for each variable -- see code.",
"Destination history embedding length (k_HISTORY)",
};
discretePropertyValueChoices = new String[][] {
null,
null
};
// Continuous:
abstractContinuousClass = ConditionalTransferEntropyCalculator.class;
@ -142,12 +149,30 @@ public class AutoAnalyserCTE extends AutoAnalyser
"Conditional history embeding delay",
"Delay from conditional to destination (in time steps)"
};
commonContPropertyValueChoices = new String[][] {
null,
null,
null,
null,
null,
null,
null,
null
};
// Gaussian properties:
gaussianProperties = new String[] {
ConditionalMutualInfoCalculatorMultiVariateGaussian.PROP_BIAS_CORRECTION,
};
gaussianPropertiesFieldNames = new String[] {
"ConditionalMutualInfoCalculatorMultiVariateGaussian.PROP_BIAS_CORRECTION",
};
gaussianPropertyDescriptions = new String[] {
"Whether the analytically determined bias (as the mean of the<br/>" +
"surrogate distribution) will be subtracted from all" +
"calculated values. Default is false."
};
gaussianPropertyValueChoices = new String[][] {
{"true", "false"},
};
// KSG (Kraskov):
kraskovProperties = new String[] {
@ -157,6 +182,7 @@ public class AutoAnalyserCTE extends AutoAnalyser
ConditionalMutualInfoCalculatorMultiVariateKraskov.PROP_DYN_CORR_EXCL_TIME,
ConditionalMutualInfoCalculatorMultiVariateKraskov.PROP_NORM_TYPE,
ConditionalMutualInfoCalculatorMultiVariateKraskov.PROP_NUM_THREADS,
ConditionalMutualInfoCalculatorMultiVariateKraskov.PROP_USE_GPU,
ConditionalTransferEntropyCalculatorKraskov.PROP_KRASKOV_ALG_NUM
};
kraskovPropertiesFieldNames = new String[] {
@ -166,6 +192,7 @@ public class AutoAnalyserCTE extends AutoAnalyser
"ConditionalMutualInfoCalculatorMultiVariateKraskov.PROP_DYN_CORR_EXCL_TIME",
"ConditionalMutualInfoCalculatorMultiVariateKraskov.PROP_NORM_TYPE",
"ConditionalMutualInfoCalculatorMultiVariateKraskov.PROP_NUM_THREADS",
"ConditionalMutualInfoCalculatorMultiVariateKraskov.PROP_USE_GPU",
"PROP_KRASKOV_ALG_NUM"
};
kraskovPropertyDescriptions = new String[] {
@ -180,9 +207,19 @@ public class AutoAnalyserCTE extends AutoAnalyser
"\"MAX_NORM\" (default), otherwise \"EUCLIDEAN\" or \"EUCLIDEAN_SQUARED\" (both equivalent here)",
"Number of parallel threads to use <br/>in computation: an integer > 0 or \"USE_ALL\" " +
"(default, to indicate to use all available processors)",
"Whether to enable the GPU module (number of threads then has no bearing); boolean, default false",
"Which KSG algorithm to use (1 or 2)",
};
kraskovPropertyValueChoices = new String[][] {
{"true", "false"},
null,
null,
null,
{"MAX_NORM", "EUCLIDEAN", "EUCLIDEAN_SQUARED"},
null,
{"true", "false"},
{"1", "2"}
};
}
@Override
@ -335,11 +372,13 @@ public class AutoAnalyserCTE extends AutoAnalyser
calcProperties.classSpecificPropertyNames = gaussianProperties;
calcProperties.classSpecificPropertiesFieldNames = gaussianPropertiesFieldNames;
calcProperties.classSpecificPropertyDescriptions = gaussianPropertyDescriptions;
calcProperties.classSpecificPropertyValueChoices = gaussianPropertyValueChoices;
} else if (selectedCalcType.startsWith(CALC_TYPE_KRASKOV)) {
// The if statement will work for both MI Kraskov calculators
calcProperties.classSpecificPropertyNames = kraskovProperties;
calcProperties.classSpecificPropertiesFieldNames = kraskovPropertiesFieldNames;
calcProperties.classSpecificPropertyDescriptions = kraskovPropertyDescriptions;
calcProperties.classSpecificPropertyValueChoices = kraskovPropertyValueChoices;
} else {
calcProperties = null;
throw new Exception("No recognised calculator selected: " +

View File

@ -47,13 +47,16 @@ public abstract class AutoAnalyserChannelCalculator extends AutoAnalyser {
protected String[] gaussianProperties;
protected String[] gaussianPropertiesFieldNames;
protected String[] gaussianPropertyDescriptions;
protected String[][] gaussianPropertyValueChoices;
protected String[] kernelProperties;
protected String[] kernelPropertiesFieldNames;
protected String[] kernelPropertyDescriptions;
protected String[][] kernelPropertyValueChoices;
protected String[] kraskovProperties;
protected String[] kraskovPropertiesFieldNames;
protected String[] kraskovPropertyDescriptions;
protected String[][] kraskovPropertyValueChoices;
public AutoAnalyserChannelCalculator() {
super();
@ -207,15 +210,18 @@ public abstract class AutoAnalyserChannelCalculator extends AutoAnalyser {
calcProperties.classSpecificPropertyNames = gaussianProperties;
calcProperties.classSpecificPropertiesFieldNames = gaussianPropertiesFieldNames;
calcProperties.classSpecificPropertyDescriptions = gaussianPropertyDescriptions;
calcProperties.classSpecificPropertyValueChoices = gaussianPropertyValueChoices;
} else if (selectedCalcType.startsWith(CALC_TYPE_KRASKOV)) {
// The if statement will work for both MI Kraskov calculators
calcProperties.classSpecificPropertyNames = kraskovProperties;
calcProperties.classSpecificPropertiesFieldNames = kraskovPropertiesFieldNames;
calcProperties.classSpecificPropertyDescriptions = kraskovPropertyDescriptions;
calcProperties.classSpecificPropertyValueChoices = kraskovPropertyValueChoices;
} else if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_KERNEL)) {
calcProperties.classSpecificPropertyNames = kernelProperties;
calcProperties.classSpecificPropertiesFieldNames = kernelPropertiesFieldNames;
calcProperties.classSpecificPropertyDescriptions = kernelPropertyDescriptions;
calcProperties.classSpecificPropertyValueChoices = kernelPropertyValueChoices;
} else {
calcProperties = null;
throw new Exception("No recognised calculator selected: " +

View File

@ -52,12 +52,15 @@ public class AutoAnalyserEntropy extends AutoAnalyser {
protected String[] gaussianProperties;
protected String[] gaussianPropertiesFieldNames;
protected String[] gaussianPropertyDescriptions;
protected String[][] gaussianPropertyValueChoices;
protected String[] kernelProperties;
protected String[] kernelPropertiesFieldNames;
protected String[] kernelPropertyDescriptions;
protected String[][] kernelPropertyValueChoices;
protected String[] klProperties;
protected String[] klPropertiesFieldNames;
protected String[] klPropertyDescriptions;
protected String[][] klPropertyValueChoices;
public AutoAnalyserEntropy() {
super();
@ -100,6 +103,9 @@ public class AutoAnalyserEntropy extends AutoAnalyser {
discretePropertyDescriptions = new String[] {
"Number of discrete states available for each variable (i.e. 2 for binary)"
};
discretePropertyValueChoices = new String[][] {
null
};
// Continuous:
abstractContinuousClass = EntropyCalculator.class;
@ -113,6 +119,9 @@ public class AutoAnalyserEntropy extends AutoAnalyser {
commonContPropertyDescriptions = new String[] {
// None
};
commonContPropertyValueChoices = new String[][] {
// None
};
// Gaussian properties:
gaussianProperties = new String[] {
};
@ -120,6 +129,8 @@ public class AutoAnalyserEntropy extends AutoAnalyser {
};
gaussianPropertyDescriptions = new String[] {
};
gaussianPropertyValueChoices = new String[][] {
};
// Kernel:
kernelProperties = new String[] {
EntropyCalculatorKernel.KERNEL_WIDTH_PROP_NAME,
@ -134,7 +145,11 @@ public class AutoAnalyserEntropy extends AutoAnalyser {
EntropyCalculatorKernel.NORMALISE_PROP_NAME +
" is set, then this is a number of standard deviations; " +
"otherwise it is an absolute value.",
"(boolean) whether to normalise <br/>the incoming time-series to mean 0, standard deviation 1, or not (recommended)",
"(boolean) whether to normalise <br/>the incoming time-series to mean 0, standard deviation 1, or not (default true, recommended)",
};
kernelPropertyValueChoices = new String[][] {
null,
{"true", "false"}
};
// KSG (Kraskov):
klProperties = new String[] {
@ -145,6 +160,8 @@ public class AutoAnalyserEntropy extends AutoAnalyser {
};
klPropertyDescriptions = new String[] {
};
klPropertyValueChoices = new String[][] {
};
}
@Override
@ -251,14 +268,17 @@ public class AutoAnalyserEntropy extends AutoAnalyser {
calcProperties.classSpecificPropertyNames = gaussianProperties;
calcProperties.classSpecificPropertiesFieldNames = gaussianPropertiesFieldNames;
calcProperties.classSpecificPropertyDescriptions = gaussianPropertyDescriptions;
calcProperties.classSpecificPropertyValueChoices = gaussianPropertyValueChoices;
} else if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_KOZ_LEO)) {
calcProperties.classSpecificPropertyNames = klProperties;
calcProperties.classSpecificPropertiesFieldNames = klPropertiesFieldNames;
calcProperties.classSpecificPropertyDescriptions = klPropertyDescriptions;
calcProperties.classSpecificPropertyValueChoices = klPropertyValueChoices;
} else if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_KERNEL)) {
calcProperties.classSpecificPropertyNames = kernelProperties;
calcProperties.classSpecificPropertiesFieldNames = kernelPropertiesFieldNames;
calcProperties.classSpecificPropertyDescriptions = kernelPropertyDescriptions;
calcProperties.classSpecificPropertyValueChoices = kernelPropertyValueChoices;
} else {
calcProperties = null;
throw new Exception("No recognised calculator selected: " +

View File

@ -92,6 +92,10 @@ public class AutoAnalyserMI extends AutoAnalyserChannelCalculator
"Number of discrete states available for each variable (i.e. 2 for binary)",
"Time-lag from source to dest to consider MI across; must be >= 0 (0 for standard MI)",
};
discretePropertyValueChoices = new String[][] {
null,
null
};
// Continuous:
abstractContinuousClass = MutualInfoCalculatorMultiVariate.class;
@ -105,12 +109,23 @@ public class AutoAnalyserMI extends AutoAnalyserChannelCalculator
commonContPropertyDescriptions = new String[] {
"Time-lag from source to dest to consider MI across; must be >= 0 (0 for standard MI)"
};
commonContPropertyValueChoices = new String[][] {
null
};
// Gaussian properties:
gaussianProperties = new String[] {
MutualInfoCalculatorMultiVariateGaussian.PROP_BIAS_CORRECTION
};
gaussianPropertiesFieldNames = new String[] {
"PROP_BIAS_CORRECTION"
};
gaussianPropertyDescriptions = new String[] {
"Whether the analytically determined bias (as the mean of the<br/>" +
"surrogate distribution) will be subtracted from all" +
"calculated values. Default is false."
};
gaussianPropertyValueChoices = new String[][] {
{"true", "false"}
};
// Kernel:
kernelProperties = new String[] {
@ -132,6 +147,11 @@ public class AutoAnalyserMI extends AutoAnalyserChannelCalculator
"0 (default) means no dynamic exclusion window",
"(boolean) whether to normalise <br/>each incoming time-series to mean 0, standard deviation 1, or not (recommended)",
};
kernelPropertyValueChoices = new String[][] {
null,
null,
{"true", "false"}
};
// KSG (Kraskov):
kraskovProperties = new String[] {
MutualInfoCalculatorMultiVariateKraskov.PROP_NORMALISE,
@ -165,7 +185,15 @@ public class AutoAnalyserMI extends AutoAnalyserChannelCalculator
"(default, to indicate to use all available processors)",
"Whether to enable the GPU module (number of threads then has no bearing); boolean, default false"
};
kraskovPropertyValueChoices = new String[][] {
{"true", "false"},
null,
null,
null,
{"MAX_NORM", "EUCLIDEAN", "EUCLIDEAN_SQUARED"},
null,
{"true", "false"},
};
}
/**
@ -213,11 +241,26 @@ public class AutoAnalyserMI extends AutoAnalyserChannelCalculator
}
return new DiscreteCalcAndArguments(
new MutualInformationCalculatorDiscrete(base, timeDiff),
new MutualInformationCalculatorDiscrete(base, base, timeDiff),
base,
base + ", " + timeDiff);
base + ", " + base + ", " + timeDiff);
}
@Override
protected String pythonSetObsSuffix() {
String selectedCalcType = (String)
calcTypeComboBox.getSelectedItem();
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE) ||
selectedCalcType.equalsIgnoreCase(CALC_TYPE_BINNED)) {
return "";
} else {
// For the moment we could direct all calls to the 1D arrays version,
// but it is working fine with JPype 0.7; later
// when we have 2D inputs we should dynamically detect that and return "2D"
return "";
}
}
/**
* @param args
*/

Some files were not shown because too many files have changed in this diff Show More