diff --git a/demos/AutoAnalyser/runMIAutoAnalyser.bat b/demos/AutoAnalyser/runMIAutoAnalyser.bat new file mode 100755 index 0000000..cb6a832 --- /dev/null +++ b/demos/AutoAnalyser/runMIAutoAnalyser.bat @@ -0,0 +1,8 @@ +@ECHO OFF + +REM Make sure the latest example source file is compiled. +javac -classpath "..\java;..\..\infodynamics.jar" "..\java\infodynamics\demos\autoanalysis\AutoAnalyserMI.java" + +REM Run the example: +java -classpath "..\java;..\..\infodynamics.jar" infodynamics.demos.autoanalysis.AutoAnalyserMI + diff --git a/demos/AutoAnalyser/runMIAutoAnalyser.sh b/demos/AutoAnalyser/runMIAutoAnalyser.sh new file mode 100755 index 0000000..0b614d0 --- /dev/null +++ b/demos/AutoAnalyser/runMIAutoAnalyser.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# Make sure the latest example source file is compiled. +javac -classpath "../java:../../infodynamics.jar" "../java/infodynamics/demos/autoanalysis/AutoAnalyserMI.java" + +# Run the example: +java -classpath "../java:../../infodynamics.jar" infodynamics.demos.autoanalysis.AutoAnalyserMI + diff --git a/demos/AutoAnalyser/runTEAutoAnalyser.bat b/demos/AutoAnalyser/runTEAutoAnalyser.bat index f1d923e..01b5435 100755 --- a/demos/AutoAnalyser/runTEAutoAnalyser.bat +++ b/demos/AutoAnalyser/runTEAutoAnalyser.bat @@ -3,6 +3,6 @@ REM Make sure the latest example source file is compiled. javac -classpath "..\java;..\..\infodynamics.jar" "..\java\infodynamics\demos\autoanalysis\AutoAnalyserTE.java" -# Run the example: +REM Run the example: java -classpath "..\java;..\..\infodynamics.jar" infodynamics.demos.autoanalysis.AutoAnalyserTE diff --git a/demos/java/infodynamics/demos/autoanalysis/AutoAnalyser.java b/demos/java/infodynamics/demos/autoanalysis/AutoAnalyser.java index 6e2d9ba..f94a037 100644 --- a/demos/java/infodynamics/demos/autoanalysis/AutoAnalyser.java +++ b/demos/java/infodynamics/demos/autoanalysis/AutoAnalyser.java @@ -300,8 +300,12 @@ public abstract class AutoAnalyser extends JFrame // Set up for ~18 rows maximum (the +6 is exact to fit all props // for Kraskov TE in without scrollbar) Dimension d = propertiesTable.getPreferredSize(); + int rowHeight = propertiesTable.getRowHeight(); propsTableScrollPane.setPreferredSize( - new Dimension(d.width,propertiesTable.getRowHeight()*17+6)); + new Dimension(d.width,rowHeight*17+6)); + propsTableScrollPane.setMinimumSize( + new Dimension(d.width,rowHeight*17+6)); + System.out.println("Row height was " + rowHeight); // Button to compute @@ -650,7 +654,8 @@ public abstract class AutoAnalyser extends JFrame calcContinuous.getClass().getSimpleName() + "\n"; matlabConstructorLine = "calc = javaObject('infodynamics.measures.continuous.gaussian." + calcContinuous.getClass().getSimpleName() + "');\n"; - } else if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_KRASKOV)) { + } else if (selectedCalcType.startsWith(CALC_TYPE_KRASKOV)) { + // The if statement will work for both MI Kraskov calculators // Cover the calculator and any references to conditional MI calculator properties javaCode.append("import infodynamics.measures.continuous.kraskov.*;\n"); javaConstructorLine = " calc = new " + calcContinuous.getClass().getSimpleName() + "();\n"; @@ -1106,7 +1111,8 @@ public abstract class AutoAnalyser extends JFrame classSpecificPropertyNames = gaussianProperties; classSpecificPropertiesFieldNames = gaussianPropertiesFieldNames; classSpecificPropertyDescriptions = gaussianPropertyDescriptions; - } else if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_KRASKOV)) { + } else if (selectedCalcType.startsWith(CALC_TYPE_KRASKOV)) { + // The if statement will work for both MI Kraskov calculators classSpecificPropertyNames = kraskovProperties; classSpecificPropertiesFieldNames = kraskovPropertiesFieldNames; classSpecificPropertyDescriptions = kraskovPropertyDescriptions; diff --git a/demos/java/infodynamics/demos/autoanalysis/AutoAnalyserMI.java b/demos/java/infodynamics/demos/autoanalysis/AutoAnalyserMI.java new file mode 100644 index 0000000..5a2b39e --- /dev/null +++ b/demos/java/infodynamics/demos/autoanalysis/AutoAnalyserMI.java @@ -0,0 +1,221 @@ +/* + * Java Information Dynamics Toolkit (JIDT) + * Copyright (C) 2015, 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 . + */ + +package infodynamics.demos.autoanalysis; + +import infodynamics.measures.continuous.ChannelCalculatorCommon; +import infodynamics.measures.continuous.MutualInfoCalculatorMultiVariate; +import infodynamics.measures.continuous.gaussian.MutualInfoCalculatorMultiVariateGaussian; +import infodynamics.measures.continuous.kernel.MutualInfoCalculatorMultiVariateKernel; +import infodynamics.measures.continuous.kraskov.MutualInfoCalculatorMultiVariateKraskov; +import infodynamics.measures.continuous.kraskov.MutualInfoCalculatorMultiVariateKraskov1; +import infodynamics.measures.continuous.kraskov.MutualInfoCalculatorMultiVariateKraskov2; +import infodynamics.measures.discrete.MutualInformationCalculatorDiscrete; + +import javax.swing.JOptionPane; +import javax.swing.event.DocumentListener; + +import java.awt.event.ActionListener; +import java.awt.event.MouseListener; + +/** + * This class provides a GUI to build a simple mutual information calculation, + * and supply the code to execute it. + * + * + * @author Joseph Lizier + * + */ +public class AutoAnalyserMI extends AutoAnalyser + implements ActionListener, DocumentListener, MouseListener { + + /** + * Need serialVersionUID to be serializable + */ + private static final long serialVersionUID = 1L; + + protected static final String DISCRETE_PROPNAME_TIME_DIFF = "time difference"; + + 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"; + + /** + * Constructor to initialise the GUI for MI + */ + protected void makeSpecificInitialisations() { + + // Set up the properties for MI: + measureAcronym = "MI"; + appletTitle = "JIDT Mutual Information Auto-Analyser"; + + calcTypes = new String[] { + CALC_TYPE_DISCRETE, CALC_TYPE_GAUSSIAN, + CALC_TYPE_KRASKOV_ALG1, CALC_TYPE_KRASKOV_ALG2, + CALC_TYPE_KERNEL}; + unitsForEachCalc = new String[] {"bits", "nats", "nats", "nats", "bits"}; + + // Discrete: + discreteClass = MutualInformationCalculatorDiscrete.class; + discreteProperties = new String[] { + DISCRETE_PROPNAME_BASE, + DISCRETE_PROPNAME_TIME_DIFF + }; + discretePropertyDefaultValues = new String[] { + "2", + "0", + }; + discretePropertyDescriptions = new String[] { + "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)", + }; + + // Continuous: + abstractContinuousClass = MutualInfoCalculatorMultiVariate.class; + // Common properties for all continuous calcs: + commonContPropertyNames = new String[] { + MutualInfoCalculatorMultiVariate.PROP_TIME_DIFF + }; + commonContPropertiesFieldNames = new String[] { + "PROP_TIME_DIFF" + }; + commonContPropertyDescriptions = new String[] { + "Time-lag from source to dest to consider MI across; must be >= 0 (0 for standard MI)" + }; + // Gaussian properties: + gaussianProperties = new String[] { + }; + gaussianPropertiesFieldNames = new String[] { + }; + gaussianPropertyDescriptions = new String[] { + }; + // Kernel: + kernelProperties = new String[] { + MutualInfoCalculatorMultiVariateKernel.KERNEL_WIDTH_PROP_NAME, + MutualInfoCalculatorMultiVariateKernel.DYN_CORR_EXCL_TIME_NAME, + MutualInfoCalculatorMultiVariateKernel.NORMALISE_PROP_NAME, + }; + kernelPropertiesFieldNames = new String[] { + "KERNEL_WIDTH_PROP_NAME", + "DYN_CORR_EXCL_TIME_NAME", + "NORMALISE_PROP_NAME" + }; + kernelPropertyDescriptions = new String[] { + "Kernel width to be used in the calculation.
If the property " + + MutualInfoCalculatorMultiVariateKernel.NORMALISE_PROP_NAME + + " is set, then this is a number of standard deviations; " + + "otherwise it is an absolute value.", + "Dynamic correlation exclusion time or
Theiler window (see Kantz and Schreiber); " + + "0 (default) means no dynamic exclusion window", + "(boolean) whether to normalise
each incoming time-series to mean 0, standard deviation 1, or not (recommended)", + }; + // KSG (Kraskov): + kraskovProperties = new String[] { + MutualInfoCalculatorMultiVariateKraskov.PROP_NORMALISE, + MutualInfoCalculatorMultiVariateKraskov.PROP_K, + MutualInfoCalculatorMultiVariateKraskov.PROP_ADD_NOISE, + MutualInfoCalculatorMultiVariateKraskov.PROP_DYN_CORR_EXCL_TIME, + MutualInfoCalculatorMultiVariateKraskov.PROP_NORM_TYPE, + MutualInfoCalculatorMultiVariateKraskov.PROP_NUM_THREADS, + }; + kraskovPropertiesFieldNames = new String[] { + "MutualInfoCalculatorMultiVariateKraskov.PROP_NORMALISE", + "MutualInfoCalculatorMultiVariateKraskov.PROP_K", + "MutualInfoCalculatorMultiVariateKraskov.PROP_ADD_NOISE", + "MutualInfoCalculatorMultiVariateKraskov.PROP_DYN_CORR_EXCL_TIME", + "MutualInfoCalculatorMultiVariateKraskov.PROP_NORM_TYPE", + "MutualInfoCalculatorMultiVariateKraskov.PROP_NUM_THREADS", + }; + kraskovPropertyDescriptions = new String[] { + "(boolean) whether to normalise
each incoming time-series to mean 0, standard deviation 1, or not (recommended)", + "Number of k nearest neighbours to use
in the full joint kernel space in the KSG algorithm", + "Standard deviation for an amount
of random Gaussian noise to add to each variable, " + + "to avoid having neighbourhoods with artificially large counts.
" + + "(\"false\" may be used to indicate \"0\".). The amount is added in after any normalisation.", + "Dynamic correlation exclusion time or
Theiler window (see Kantz and Schreiber); " + + "0 (default) means no dynamic exclusion window", + "
Norm type to use in KSG algorithm between the points in each marginal space.
Options are: " + + "\"MAX_NORM\" (default), otherwise \"EUCLIDEAN\" or \"EUCLIDEAN_SQUARED\" (both equivalent here)", + "Number of parallel threads to use
in computation: an integer > 0 or \"USE_ALL\" " + + "(default, to indicate to use all available processors)", + }; + + } + + /** + * Method to assign and initialise our continuous calculator class + */ + protected ChannelCalculatorCommon assignCalcObjectContinuous(String selectedCalcType) throws Exception { + if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_GAUSSIAN)) { + return new MutualInfoCalculatorMultiVariateGaussian(); + } else if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_KRASKOV_ALG1)) { + return new MutualInfoCalculatorMultiVariateKraskov1(); + } else if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_KRASKOV_ALG2)) { + return new MutualInfoCalculatorMultiVariateKraskov2(); + } else if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_KERNEL)) { + return new MutualInfoCalculatorMultiVariateKernel(); + } else { + throw new Exception("No recognised continuous calculator selected: " + + selectedCalcType); + } + + } + + /** + * Method to assign and initialise our discrete calculator class + */ + protected DiscreteCalcAndArguments assignCalcObjectDiscrete() throws Exception { + String timeDiffPropValueStr, basePropValueStr; + try { + timeDiffPropValueStr = propertyValues.get(DISCRETE_PROPNAME_TIME_DIFF); + } catch (Exception ex) { + JOptionPane.showMessageDialog(this, + ex.getMessage()); + resultsLabel.setText("Cannot find a value for property " + DISCRETE_PROPNAME_TIME_DIFF); + return null; + } + try { + basePropValueStr = propertyValues.get(DISCRETE_PROPNAME_BASE); + } catch (Exception ex) { + JOptionPane.showMessageDialog(this, + ex.getMessage()); + resultsLabel.setText("Cannot find a value for property " + DISCRETE_PROPNAME_BASE); + return null; + } + int timeDiff = Integer.parseInt(timeDiffPropValueStr); + int base = Integer.parseInt(basePropValueStr); + + return new DiscreteCalcAndArguments( + new MutualInformationCalculatorDiscrete(base, timeDiff), + base, + base + ", " + timeDiff); + } + + protected void setObservations(ChannelCalculatorCommon calc, + double[] source, double[] dest) throws Exception { + // We know this is a MutualInfoCalculatorMultiVariate + MutualInfoCalculatorMultiVariate miCalc = (MutualInfoCalculatorMultiVariate) calc; + miCalc.setObservations(source, dest); + } + + /** + * @param args + */ + public static void main(String[] args) { + new AutoAnalyserMI(); + } +} diff --git a/demos/java/infodynamics/demos/autoanalysis/AutoAnalyserTE.java b/demos/java/infodynamics/demos/autoanalysis/AutoAnalyserTE.java index 7d76997..652c361 100644 --- a/demos/java/infodynamics/demos/autoanalysis/AutoAnalyserTE.java +++ b/demos/java/infodynamics/demos/autoanalysis/AutoAnalyserTE.java @@ -219,7 +219,7 @@ public class AutoAnalyserTE extends AutoAnalyser } catch (Exception ex) { JOptionPane.showMessageDialog(this, ex.getMessage()); - resultsLabel.setText("Cannot find a value for property " + DISCRETE_PROPNAME_BASE); + resultsLabel.setText("Cannot find a value for property " + DISCRETE_PROPNAME_K); return null; } try {