mirror of https://github.com/jlizier/jidt
Split AutoAnalyser into 2 classes, itself and the new AutoAnalyserChannelCalculator, keeping all the common functionality/generality for other calculator types in AutoAnalyser. This will allow us to have the AutoAnalyser for other types of calculators as well later.
This commit is contained in:
parent
086bee5945
commit
e75eb761ca
|
|
@ -18,12 +18,13 @@
|
|||
|
||||
package infodynamics.demos.autoanalysis;
|
||||
|
||||
import infodynamics.measures.continuous.ChannelCalculatorCommon;
|
||||
import infodynamics.measures.discrete.ChannelCalculatorDiscrete;
|
||||
import infodynamics.measures.continuous.InfoMeasureCalculatorContinuous;
|
||||
import infodynamics.measures.discrete.InfoMeasureCalculatorDiscrete;
|
||||
import infodynamics.utils.AnalyticMeasurementDistribution;
|
||||
import infodynamics.utils.AnalyticNullDistributionComputer;
|
||||
import infodynamics.utils.ArrayFileReader;
|
||||
import infodynamics.utils.EmpiricalMeasurementDistribution;
|
||||
import infodynamics.utils.EmpiricalNullDistributionComputer;
|
||||
import infodynamics.utils.MatrixUtils;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
|
|
@ -89,13 +90,16 @@ public abstract class AutoAnalyser extends JFrame
|
|||
|
||||
// Set options for the Calculator type:
|
||||
public final static String CALC_TYPE_DISCRETE = "Discrete";
|
||||
// Child classes must define options for other calculator types
|
||||
// and initialise the calcTypes array and unitsForEachCalc array
|
||||
protected String[] calcTypes;
|
||||
protected String[] unitsForEachCalc;
|
||||
|
||||
// Set additional general options for the Calculator type:
|
||||
public final static String CALC_TYPE_GAUSSIAN = "Gaussian";
|
||||
public final static String CALC_TYPE_KRASKOV = "Kraskov (KSG)";
|
||||
public final static String CALC_TYPE_KERNEL = "Kernel";
|
||||
protected String[] calcTypes = {
|
||||
CALC_TYPE_DISCRETE, CALC_TYPE_GAUSSIAN,
|
||||
CALC_TYPE_KRASKOV, CALC_TYPE_KERNEL};
|
||||
protected String[] unitsForEachCalc = {"bits", "nats", "nats", "bits"};
|
||||
public final static String CALC_TYPE_KOZ_LEO = "Kozachenko-Leonenko";
|
||||
|
||||
// Properties for each calculator
|
||||
protected static final String DISCRETE_PROPNAME_BASE = "base";
|
||||
|
|
@ -107,16 +111,15 @@ public abstract class AutoAnalyser extends JFrame
|
|||
protected String[] commonContPropertyNames;
|
||||
protected String[] commonContPropertiesFieldNames;
|
||||
protected String[] commonContPropertyDescriptions;
|
||||
protected String[] gaussianProperties;
|
||||
protected String[] gaussianPropertiesFieldNames;
|
||||
protected String[] gaussianPropertyDescriptions;
|
||||
protected String[] kernelProperties;
|
||||
protected String[] kernelPropertiesFieldNames;
|
||||
protected String[] kernelPropertyDescriptions;
|
||||
protected String[] kraskovProperties;
|
||||
protected String[] kraskovPropertiesFieldNames;
|
||||
protected String[] kraskovPropertyDescriptions;
|
||||
// Children can define properties for specific continuous
|
||||
// calculators
|
||||
|
||||
// Number of variables that this measure operates on (1 to 3)
|
||||
protected int numVariables = 1;
|
||||
// Labels for each of the fields to enter the column number for the variables.
|
||||
// Should be overridden by the child classes.
|
||||
protected String[] variableColNumLabels = null;
|
||||
|
||||
// Store which calculator type we're using:
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected Class calcClass = null;
|
||||
|
|
@ -128,6 +131,11 @@ public abstract class AutoAnalyser extends JFrame
|
|||
|
||||
protected String measureAcronym = null;
|
||||
|
||||
// String to describe the relationship between the variables
|
||||
// being measured here, with format tokens %%d in order for
|
||||
// each variable. To be assigned by the child class.
|
||||
protected String variableRelationshipFormatString = null;
|
||||
|
||||
protected JButton computeButton;
|
||||
protected JButton openDataButton;
|
||||
// Stores the current data file
|
||||
|
|
@ -145,12 +153,19 @@ public abstract class AutoAnalyser extends JFrame
|
|||
// Number of rows and columns of the data:
|
||||
protected int dataRows = 0;
|
||||
protected int dataColumns = 0;
|
||||
// Source column field
|
||||
protected JTextField sourceColTextField;
|
||||
// Destination column field
|
||||
protected JTextField destColTextField;
|
||||
// CheckBox for "all pairs?"
|
||||
protected JCheckBox allPairsCheckBox;
|
||||
// Boolean for whether we include the all combinations checkbox and label on the GUI
|
||||
// (default false). Child classes can alter this in makeSpecificInitialisations()
|
||||
protected boolean useAllCombosCheckBox = false;
|
||||
// Which word should be used to describe combinations for this measure? "pairs", "variables", etc?
|
||||
// Child classes should override this.
|
||||
protected String wordForCombinations = null;
|
||||
// CheckBox for "all variables?" OR "all pairs?"
|
||||
protected JCheckBox allCombosCheckBox;
|
||||
// Variable text fields
|
||||
protected JTextField[] variableColTextFields;
|
||||
// Boolean for whether we include the statistical significance checkbox and label on the GUI
|
||||
// (default false). Child classes can alter this in makeSpecificInitialisations()
|
||||
protected boolean useStatSigCheckBox = false;
|
||||
// CheckBox for statistical significance
|
||||
protected JCheckBox statSigCheckBox;
|
||||
// CheckBox for statistical significance analytically
|
||||
|
|
@ -252,7 +267,7 @@ public abstract class AutoAnalyser extends JFrame
|
|||
Image watermarkImage = (new ImageIcon("JIDT-logo-watermark.png")).getImage();
|
||||
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setSize(1100,640);
|
||||
setSize(1100,670);
|
||||
setTitle(appletTitle);
|
||||
// Centre in the middle of the screen
|
||||
setLocationRelativeTo(null);
|
||||
|
|
@ -262,7 +277,7 @@ public abstract class AutoAnalyser extends JFrame
|
|||
calcTypeLabel.setToolTipText("Select estimator type. \"Discrete\" is for discrete or pre-binned data; all others for continuous data.");
|
||||
calcTypeLabel.setBorder(BorderFactory.createEmptyBorder(0,0,10,0));
|
||||
calcTypeComboBox = (JComboBox<String>) new JComboBox<String>(calcTypes);
|
||||
calcTypeComboBox.setSelectedIndex(2); // Select Kraskov by default
|
||||
calcTypeComboBox.setSelectedIndex(2); // Select 2nd continuous estimator by default
|
||||
calcTypeComboBox.addActionListener(this);
|
||||
// Don't set an empty border as it becomes clickable as well,
|
||||
// we'll use an empty label instead
|
||||
|
|
@ -270,7 +285,7 @@ public abstract class AutoAnalyser extends JFrame
|
|||
|
||||
// Create the fields for the data file
|
||||
JLabel fileLabel = new JLabel("Data file:");
|
||||
fileLabel.setToolTipText("Must be a text file of time-series values with time increasing in rows, and variables along columns");
|
||||
fileLabel.setToolTipText("Must be a text file of samples or time-series values with time/sample increasing in rows, and variables along columns");
|
||||
dataFileTextField = new JTextField(30);
|
||||
dataFileTextField.setEnabled(false);
|
||||
dataFileTextField.addMouseListener(this);
|
||||
|
|
@ -283,29 +298,29 @@ public abstract class AutoAnalyser extends JFrame
|
|||
dataFileDescriptorLabel.setHorizontalAlignment(JLabel.RIGHT);
|
||||
dataFileDescriptorLabel.setBorder(BorderFactory.createEmptyBorder(0,0,10,0));
|
||||
|
||||
// From column:
|
||||
JLabel sourceLabel = new JLabel("Source column:");
|
||||
sourceLabel.setToolTipText("First column is 0.");
|
||||
sourceColTextField = new JTextField(5);
|
||||
sourceColTextField.setEnabled(true);
|
||||
sourceColTextField.setText("0");
|
||||
// Must add document listener, not add action listener
|
||||
sourceColTextField.getDocument().addDocumentListener(this);
|
||||
// To column:
|
||||
JLabel destLabel = new JLabel("Destination column:");
|
||||
destLabel.setToolTipText("First column is 0.");
|
||||
destLabel.setBorder(BorderFactory.createEmptyBorder(0,0,10,0));
|
||||
destColTextField = new JTextField(5);
|
||||
destColTextField.setEnabled(true);
|
||||
destColTextField.setText("1");
|
||||
destColTextField.getDocument().addDocumentListener(this);
|
||||
// We define the all combos checkbox, but we won't add it later
|
||||
// if it's not used for this measure type.
|
||||
allCombosCheckBox = new JCheckBox("All " + wordForCombinations + "?");
|
||||
allCombosCheckBox.setToolTipText("Compute for all column " + wordForCombinations + "?");
|
||||
allCombosCheckBox.addChangeListener(this);
|
||||
|
||||
variableColTextFields = new JTextField[numVariables];
|
||||
JLabel[] labels = new JLabel[numVariables];
|
||||
for (int i = 0; i < numVariables; i++) {
|
||||
labels[i] = new JLabel(variableColNumLabels[i] + " column:");
|
||||
labels[i].setToolTipText("First column is 0.");
|
||||
// This border was only done on the 2nd variable before, so may need
|
||||
// to restrict its use:
|
||||
labels[i].setBorder(BorderFactory.createEmptyBorder(0,0,10,0));
|
||||
variableColTextFields[i] = new JTextField(5);
|
||||
variableColTextFields[i].setEnabled(true);
|
||||
variableColTextFields[i].setText(Integer.toString(i));
|
||||
// Must add document listener, not add action listener
|
||||
variableColTextFields[i].getDocument().addDocumentListener(this);
|
||||
}
|
||||
|
||||
// Checkbox for all pairs
|
||||
allPairsCheckBox = new JCheckBox("All pairs?");
|
||||
allPairsCheckBox.setToolTipText("Compute for all pairs of columns?");
|
||||
allPairsCheckBox.addChangeListener(this);
|
||||
|
||||
// CheckBox for statistical signficance
|
||||
// We define the CheckBox for statistical signficance,
|
||||
// but we won't add it later if it's not used for this measure type.
|
||||
statSigCheckBox = new JCheckBox("Add stat. signif.?");
|
||||
statSigCheckBox.setToolTipText("Compute the null surrogate distribution under the null hypothesis that source and target are not related?");
|
||||
statSigCheckBox.addChangeListener(this);
|
||||
|
|
@ -465,42 +480,40 @@ public abstract class AutoAnalyser extends JFrame
|
|||
|
||||
paramsPanel.add(dataFileDescriptorLabel, c);
|
||||
|
||||
// Add the all pairs label and checkbox
|
||||
c.gridwidth = GridBagConstraints.REMAINDER; //end row
|
||||
c.gridx = 1;
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.weightx = 1.0;
|
||||
paramsPanel.add(allPairsCheckBox, c);
|
||||
c.gridx = -1; // reset to no indication
|
||||
|
||||
// Add the source selector
|
||||
c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last
|
||||
c.fill = GridBagConstraints.NONE; //reset to default
|
||||
c.weightx = 0.0; //reset to default
|
||||
paramsPanel.add(sourceLabel, c);
|
||||
c.gridwidth = GridBagConstraints.REMAINDER; //end row
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.weightx = 1.0;
|
||||
paramsPanel.add(sourceColTextField, c);
|
||||
// Add the destination selector
|
||||
c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last
|
||||
c.fill = GridBagConstraints.NONE; //reset to default
|
||||
c.weightx = 0.0; //reset to default
|
||||
paramsPanel.add(destLabel, c);
|
||||
c.gridwidth = GridBagConstraints.REMAINDER; //end row
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.weightx = 1.0;
|
||||
paramsPanel.add(destColTextField, c);
|
||||
if (useAllCombosCheckBox) {
|
||||
// Add the all combos label and checkbox
|
||||
c.gridwidth = GridBagConstraints.REMAINDER; //end row
|
||||
c.gridx = 1;
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.weightx = 1.0;
|
||||
paramsPanel.add(allCombosCheckBox, c);
|
||||
c.gridx = -1; // reset to no indication
|
||||
}
|
||||
|
||||
// Add the CheckBoxes for statistical significance checks:
|
||||
c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last
|
||||
c.fill = GridBagConstraints.NONE; //reset to default
|
||||
c.weightx = 0.0; //reset to default
|
||||
paramsPanel.add(statSigCheckBox, c);
|
||||
c.gridwidth = GridBagConstraints.REMAINDER; //end row
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.weightx = 1.0;
|
||||
paramsPanel.add(statSigAnalyticCheckBox, c);
|
||||
// Add the column number selectors
|
||||
for (int i = 0; i < numVariables; i++) {
|
||||
// Add the column selector for variable i
|
||||
c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last
|
||||
c.fill = GridBagConstraints.NONE; //reset to default
|
||||
c.weightx = 0.0; //reset to default
|
||||
paramsPanel.add(labels[i], c);
|
||||
c.gridwidth = GridBagConstraints.REMAINDER; //end row
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.weightx = 1.0;
|
||||
paramsPanel.add(variableColTextFields[i], c);
|
||||
}
|
||||
|
||||
if (useStatSigCheckBox) {
|
||||
// Add the CheckBoxes for statistical significance checks:
|
||||
c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last
|
||||
c.fill = GridBagConstraints.NONE; //reset to default
|
||||
c.weightx = 0.0; //reset to default
|
||||
paramsPanel.add(statSigCheckBox, c);
|
||||
c.gridwidth = GridBagConstraints.REMAINDER; //end row
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.weightx = 1.0;
|
||||
paramsPanel.add(statSigAnalyticCheckBox, c);
|
||||
}
|
||||
|
||||
// Add dummy label for spacing
|
||||
paramsPanel.add(dummyLabel1, c);
|
||||
|
|
@ -579,7 +592,6 @@ public abstract class AutoAnalyser extends JFrame
|
|||
statSigAnalyticCheckBox.setSelected(false);
|
||||
statSigAnalyticCheckBox.setEnabled(false);
|
||||
}
|
||||
|
||||
}
|
||||
// Else nothing extra to do
|
||||
}
|
||||
|
|
@ -673,34 +685,24 @@ public abstract class AutoAnalyser extends JFrame
|
|||
return;
|
||||
}
|
||||
|
||||
int singleSourceColumn = -1, singleDestColumn = -1;
|
||||
Vector<int[]> sourceDestPairs = new Vector<int[]>();
|
||||
if (allPairsCheckBox.isSelected()) {
|
||||
// We're doing all pairs
|
||||
for (int s = 0; s < dataColumns; s++) {
|
||||
for (int d = 0; d < dataColumns; d++) {
|
||||
sourceDestPairs.add(new int[] {s, d});
|
||||
int[] singleCalcColumns = new int[numVariables];
|
||||
Vector<int[]> variableCombinations = new Vector<int[]>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// we're doing a single source-destination pair
|
||||
singleSourceColumn = Integer.parseInt(sourceColTextField.getText());
|
||||
singleDestColumn = Integer.parseInt(destColTextField.getText());
|
||||
sourceDestPairs.add(new int[] {singleSourceColumn, singleDestColumn});
|
||||
if ((singleSourceColumn < 0) || (singleSourceColumn >= dataColumns)) {
|
||||
JOptionPane.showMessageDialog(this,
|
||||
String.format("Source column must be between 0 and %d for this data set",
|
||||
dataColumns-1));
|
||||
resultsLabel.setText(" ");
|
||||
return;
|
||||
}
|
||||
if ((singleDestColumn < 0) || (singleDestColumn >= dataColumns)) {
|
||||
JOptionPane.showMessageDialog(this,
|
||||
String.format("Destination column must be between 0 and %d for this data set",
|
||||
dataColumns-1));
|
||||
resultsLabel.setText(" ");
|
||||
return;
|
||||
}
|
||||
variableCombinations.add(singleCalcColumns);
|
||||
}
|
||||
|
||||
// Generate headers:
|
||||
|
|
@ -745,8 +747,8 @@ public abstract class AutoAnalyser extends JFrame
|
|||
try{
|
||||
// Create both discrete and continuous calculators to make
|
||||
// following code simpler:
|
||||
ChannelCalculatorCommon calcContinuous = null;
|
||||
ChannelCalculatorDiscrete calcDiscrete = null;
|
||||
InfoMeasureCalculatorContinuous calcContinuous = null;
|
||||
InfoMeasureCalculatorDiscrete calcDiscrete = null;
|
||||
|
||||
// Construct an instance of the selected calculator:
|
||||
String javaConstructorLine = null;
|
||||
|
|
@ -781,6 +783,14 @@ public abstract class AutoAnalyser extends JFrame
|
|||
calcContinuous.getClass().getSimpleName() + "\n";
|
||||
matlabConstructorLine = "calc = javaObject('infodynamics.measures.continuous.kernel." +
|
||||
calcContinuous.getClass().getSimpleName() + "');\n";
|
||||
} else if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_KOZ_LEO)) {
|
||||
// Cover the calculator and any references to other classes
|
||||
javaCode.append("import infodynamics.measures.continuous.kozachenko.*;\n");
|
||||
javaConstructorLine = " calc = new " + calcContinuous.getClass().getSimpleName() + "();\n";
|
||||
pythonPreConstructorLine = "calcClass = JPackage(\"infodynamics.measures.continuous.kozachenko\")." +
|
||||
calcContinuous.getClass().getSimpleName() + "\n";
|
||||
matlabConstructorLine = "calc = javaObject('infodynamics.measures.continuous.kozachenko." +
|
||||
calcContinuous.getClass().getSimpleName() + "');\n";
|
||||
} else {
|
||||
throw new Exception("No recognised calculator selected: " +
|
||||
selectedCalcType);
|
||||
|
|
@ -798,15 +808,21 @@ public abstract class AutoAnalyser extends JFrame
|
|||
javaCode.append(" ArrayFileReader afr = new ArrayFileReader(dataFile);\n");
|
||||
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE)) {
|
||||
javaCode.append(" int[][] data = afr.getInt2DMatrix();\n");
|
||||
if (! allPairsCheckBox.isSelected()) {
|
||||
javaCode.append(" int[] source = MatrixUtils.selectColumn(data, " + singleSourceColumn + ");\n");
|
||||
javaCode.append(" int[] dest = MatrixUtils.selectColumn(data, " + singleDestColumn + ");\n\n");
|
||||
if (! allCombosCheckBox.isSelected()) {
|
||||
for (int i=0; i < numVariables; i++) {
|
||||
javaCode.append(" int[] " + variableColNumLabels[i].toLowerCase() +
|
||||
" = MatrixUtils.selectColumn(data, " + singleCalcColumns[i] + ");\n");
|
||||
}
|
||||
javaCode.append("\n");
|
||||
}
|
||||
} else {
|
||||
javaCode.append(" double[][] data = afr.getDouble2DMatrix();\n");
|
||||
if (! allPairsCheckBox.isSelected()) {
|
||||
javaCode.append(" double[] source = MatrixUtils.selectColumn(data, " + singleSourceColumn + ");\n");
|
||||
javaCode.append(" double[] dest = MatrixUtils.selectColumn(data, " + singleDestColumn + ");\n\n");
|
||||
if (! allCombosCheckBox.isSelected()) {
|
||||
for (int i=0; i < numVariables; i++) {
|
||||
javaCode.append(" double[] " + variableColNumLabels[i].toLowerCase() +
|
||||
" = MatrixUtils.selectColumn(data, " + singleCalcColumns[i] + ");\n");
|
||||
}
|
||||
javaCode.append("\n");
|
||||
}
|
||||
}
|
||||
// 2. Python
|
||||
|
|
@ -818,21 +834,38 @@ public abstract class AutoAnalyser extends JFrame
|
|||
}
|
||||
pythonCode.append("# As numpy array:\n");
|
||||
pythonCode.append("data = numpy.array(dataRaw)\n");
|
||||
if (! allPairsCheckBox.isSelected()) {
|
||||
pythonCode.append("source = JArray(JInt, 1)(data[:," + singleSourceColumn + "].tolist())\n");
|
||||
pythonCode.append("dest = JArray(JInt, 1)(data[:," + singleDestColumn + "].tolist())\n\n");
|
||||
if (! allCombosCheckBox.isSelected()) {
|
||||
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE)) {
|
||||
for (int i=0; i < numVariables; i++) {
|
||||
pythonCode.append(variableColNumLabels[i].toLowerCase() + " = JArray(JInt, 1)(data[:," +
|
||||
singleCalcColumns[i] + "].tolist())\n");
|
||||
}
|
||||
pythonCode.append("\n");
|
||||
} else {
|
||||
for (int i=0; i < numVariables; i++) {
|
||||
pythonCode.append(variableColNumLabels[i].toLowerCase() + " = data[:," +
|
||||
singleCalcColumns[i] + "]\n");
|
||||
}
|
||||
pythonCode.append("\n");
|
||||
}
|
||||
}
|
||||
// 3. Matlab
|
||||
matlabCode.append("% " + loadDataComment);
|
||||
matlabCode.append("data = load('" + dataFile.getAbsolutePath() + "');\n");
|
||||
if (! allPairsCheckBox.isSelected()) {
|
||||
if (! allCombosCheckBox.isSelected()) {
|
||||
matlabCode.append("% Column indices start from 1 in Matlab:\n");
|
||||
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE)) {
|
||||
matlabCode.append("source = octaveToJavaIntArray(data(:," + (singleSourceColumn+1) + "));\n");
|
||||
matlabCode.append("dest = octaveToJavaIntArray(data(:," + (singleDestColumn+1) + "));\n\n");
|
||||
for (int i=0; i < numVariables; i++) {
|
||||
matlabCode.append(variableColNumLabels[i].toLowerCase() + " = octaveToJavaIntArray(data(:," +
|
||||
(singleCalcColumns[i]+1) + "));\n");
|
||||
}
|
||||
matlabCode.append("\n");
|
||||
} else {
|
||||
matlabCode.append("source = octaveToJavaDoubleArray(data(:," + (singleSourceColumn+1) + "));\n");
|
||||
matlabCode.append("dest = octaveToJavaDoubleArray(data(:," + (singleDestColumn+1) + "));\n\n");
|
||||
for (int i=0; i < numVariables; i++) {
|
||||
matlabCode.append(variableColNumLabels[i].toLowerCase() + " = octaveToJavaDoubleArray(data(:," +
|
||||
(singleCalcColumns[i]+1) + "));\n");
|
||||
}
|
||||
matlabCode.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -936,59 +969,46 @@ public abstract class AutoAnalyser extends JFrame
|
|||
String javaPrefix = " ";
|
||||
String pythonPrefix = "";
|
||||
String matlabPrefix = "";
|
||||
if (sourceDestPairs.size() > 1) {
|
||||
// We're doing all pairs
|
||||
StringBuffer extraFormatTerms = new StringBuffer();
|
||||
if (variableCombinations.size() > 1) {
|
||||
// We're doing all combinations.
|
||||
// Set up the loops for these:
|
||||
String[] columnVariables = setUpLoopsForAllCombos(javaCode, pythonCode, matlabCode);
|
||||
|
||||
// Get the indents right from here on,
|
||||
// and prepare a string of the column labels for
|
||||
// each variable, to be used in later formatting.
|
||||
for (int i = 0; i < numVariables; i++) {
|
||||
javaPrefix += " ";
|
||||
pythonPrefix += "\t";
|
||||
matlabPrefix += "\t";
|
||||
extraFormatTerms.append(columnVariables[i] + ", ");
|
||||
}
|
||||
|
||||
// Set up loops in the code:
|
||||
// 1. Java code
|
||||
javaCode.append(" \n");
|
||||
javaCode.append(" // Compute for all pairs:\n");
|
||||
javaCode.append(" for (int s = 0; s < " + dataColumns +
|
||||
"; s++) {\n");
|
||||
javaCode.append(" for (int d = 0; d < " + dataColumns +
|
||||
"; d++) {\n");
|
||||
javaPrefix = " ";
|
||||
javaCode.append(javaPrefix + "// For each source-dest pair:\n");
|
||||
javaCode.append(javaPrefix + "if (s == d) {\n");
|
||||
javaCode.append(javaPrefix + " continue;\n");
|
||||
javaCode.append(javaPrefix + "}\n");
|
||||
// 2. Python code
|
||||
pythonCode.append("\n");
|
||||
pythonCode.append("# Compute for all pairs:\n");
|
||||
pythonCode.append("for s in range(" + dataColumns + "):\n");
|
||||
pythonCode.append("\tfor d in range(" + dataColumns + "):\n");
|
||||
pythonPrefix = "\t\t";
|
||||
pythonCode.append(pythonPrefix+ "# For each source-dest pair:\n");
|
||||
pythonCode.append(pythonPrefix + "if (s == d):\n");
|
||||
pythonCode.append(pythonPrefix + "\tcontinue\n");
|
||||
// 3. Matlab code
|
||||
matlabCode.append("\n");
|
||||
matlabCode.append("% Compute for all pairs:\n");
|
||||
matlabCode.append("for s = 1:" + dataColumns + "\n");
|
||||
matlabCode.append("\tfor d = 1:" + dataColumns + "\n");
|
||||
matlabPrefix = "\t\t";
|
||||
matlabCode.append(matlabPrefix + "% For each source-dest pair:\n");
|
||||
matlabCode.append(matlabPrefix + "if (s == d)\n");
|
||||
matlabCode.append(matlabPrefix + "\tcontinue;\n");
|
||||
matlabCode.append(matlabPrefix + "end\n");
|
||||
|
||||
// Read in the data for these columns for all pairs
|
||||
matlabCode.append(matlabPrefix + "% Column indices start from 1 in Matlab:\n");
|
||||
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE)) {
|
||||
javaCode.append(javaPrefix + "int[] source = MatrixUtils.selectColumn(data, s);\n");
|
||||
javaCode.append(javaPrefix + "int[] dest = MatrixUtils.selectColumn(data, d);\n\n");
|
||||
matlabCode.append(matlabPrefix + "source = octaveToJavaIntArray(data(:, s));\n");
|
||||
matlabCode.append(matlabPrefix + "dest = octaveToJavaIntArray(data(:, d));\n\n");
|
||||
pythonCode.append(pythonPrefix + "source = JArray(JInt, 1)(data[:, s].tolist())\n");
|
||||
pythonCode.append(pythonPrefix + "dest = JArray(JInt, 1)(data[:, d].tolist())\n\n");
|
||||
for (int i = 0; i < numVariables; i++) {
|
||||
javaCode.append(javaPrefix + "int[] " + variableColNumLabels[i].toLowerCase() +
|
||||
" = MatrixUtils.selectColumn(data, " + columnVariables[i] + ");\n");
|
||||
matlabCode.append(matlabPrefix + variableColNumLabels[i].toLowerCase() +
|
||||
" = octaveToJavaIntArray(data(:, " + columnVariables[i] + "));\n");
|
||||
pythonCode.append(pythonPrefix + variableColNumLabels[i].toLowerCase() +
|
||||
" = JArray(JInt, 1)(data[:, " + columnVariables[i] + "].tolist())\n");
|
||||
}
|
||||
} else {
|
||||
javaCode.append(javaPrefix + "double[] source = MatrixUtils.selectColumn(data, s);\n");
|
||||
javaCode.append(javaPrefix + "double[] dest = MatrixUtils.selectColumn(data, d);\n\n");
|
||||
matlabCode.append(matlabPrefix + "source = octaveToJavaDoubleArray(data(:, s));\n");
|
||||
matlabCode.append(matlabPrefix + "dest = octaveToJavaDoubleArray(data(:, d));\n\n");
|
||||
pythonCode.append(pythonPrefix + "source = data[:, s]\n");
|
||||
pythonCode.append(pythonPrefix + "dest = data[:, d]\n\n");
|
||||
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");
|
||||
}
|
||||
}
|
||||
javaCode.append("\n");
|
||||
matlabCode.append("\n");
|
||||
pythonCode.append("\n");
|
||||
} else {
|
||||
// For a single pair, we don't need to set up loops, and
|
||||
// we've already read in the data to source and dest variables above
|
||||
|
|
@ -1011,15 +1031,23 @@ public abstract class AutoAnalyser extends JFrame
|
|||
} else {
|
||||
setObservationsMethod = "setObservations";
|
||||
}
|
||||
StringBuffer methodArguments = new StringBuffer();
|
||||
for (int i = 0; i < numVariables; i++) {
|
||||
methodArguments.append(variableColNumLabels[i].toLowerCase());
|
||||
if (i < numVariables - 1) {
|
||||
// There are more variables to come:
|
||||
methodArguments.append(", ");
|
||||
}
|
||||
}
|
||||
// 1. Java
|
||||
javaCode.append(javaPrefix + "// " + supplyDataComment);
|
||||
javaCode.append(javaPrefix + "calc." + setObservationsMethod + "(source, dest);\n");
|
||||
javaCode.append(javaPrefix + "calc." + setObservationsMethod + "(" + methodArguments + ");\n");
|
||||
// 2. Python
|
||||
pythonCode.append(pythonPrefix + "# " + supplyDataComment);
|
||||
pythonCode.append(pythonPrefix + "calc." + setObservationsMethod + "(source, dest)\n");
|
||||
pythonCode.append(pythonPrefix + "calc." + setObservationsMethod + "(" + methodArguments + ")\n");
|
||||
// 3. Matlab
|
||||
matlabCode.append(matlabPrefix + "% " + supplyDataComment);
|
||||
matlabCode.append(matlabPrefix + "calc." + setObservationsMethod + "(source, dest);\n");
|
||||
matlabCode.append(matlabPrefix + "calc." + setObservationsMethod + "(" + methodArguments + ");\n");
|
||||
|
||||
// Compute the result
|
||||
String computeComment = "5. Compute the estimate:\n";
|
||||
|
|
@ -1030,15 +1058,16 @@ public abstract class AutoAnalyser extends JFrame
|
|||
matlabCode.append(matlabPrefix + "% " + computeComment);
|
||||
matlabCode.append(matlabPrefix + "result = calc.computeAverageLocalOfObservations();\n");
|
||||
|
||||
String resultsPrefixString, extraFormatTerms;
|
||||
if (sourceDestPairs.size() > 1) {
|
||||
resultsPrefixString = String.format(measureAcronym + "_%s(col_%%d -> col_%%d) = ",
|
||||
selectedCalcType);
|
||||
extraFormatTerms = "s, d, ";
|
||||
String resultsPrefixString;
|
||||
if (variableCombinations.size() > 1) {
|
||||
resultsPrefixString = String.format(measureAcronym + "_%s(%s) = ",
|
||||
selectedCalcType, variableRelationshipFormatString);
|
||||
} else {
|
||||
resultsPrefixString = String.format(measureAcronym + "_%s(col_%d -> col_%d) = ",
|
||||
selectedCalcType, singleSourceColumn, singleDestColumn);
|
||||
extraFormatTerms = "";
|
||||
resultsPrefixString = String.format(measureAcronym + "_%s(%s) = ",
|
||||
selectedCalcType,
|
||||
formatStringWithColumnNumbers(
|
||||
variableRelationshipFormatString,
|
||||
singleCalcColumns));
|
||||
}
|
||||
|
||||
String resultsSuffixString = "";
|
||||
|
|
@ -1076,18 +1105,11 @@ public abstract class AutoAnalyser extends JFrame
|
|||
"%.4f " + units + resultsSuffixString + "\\n', ...\n\t" + matlabPrefix +
|
||||
extraFormatTerms + "result" + statSigFormatTerms + ");\n");
|
||||
|
||||
if (sourceDestPairs.size() > 1) {
|
||||
// We're doing all pairs
|
||||
if (variableCombinations.size() > 1) {
|
||||
// We're doing all combos
|
||||
|
||||
// Finalise the loops in the code:
|
||||
// 1. Java code
|
||||
javaCode.append(" }\n");
|
||||
javaCode.append(" }\n");
|
||||
// 2. Python code
|
||||
// Nothing to do
|
||||
// 3. Matlab code
|
||||
matlabCode.append("\tend\n");
|
||||
matlabCode.append("end\n");
|
||||
finaliseLoopsForAllCombos(javaCode, pythonCode, matlabCode);
|
||||
|
||||
// And tell the user to see results in the console:
|
||||
resultsLabel.setText("See console for all pairs calculation results");
|
||||
|
|
@ -1126,11 +1148,11 @@ public abstract class AutoAnalyser extends JFrame
|
|||
// Now make our own calculations here:
|
||||
// TODO make the calculation in a separate thread, and have a
|
||||
// button to cancel the calculation whilst it's running
|
||||
for (int[] pair : sourceDestPairs) {
|
||||
int sourceColumn = pair[0];
|
||||
int destColumn = pair[1];
|
||||
for (int[] columnCombo : variableCombinations) {
|
||||
|
||||
if (sourceColumn == destColumn) {
|
||||
if ((variableCombinations.size() > 1) && skipColumnCombo(columnCombo)) {
|
||||
System.out.print("Skipping column combo ");
|
||||
MatrixUtils.printArray(System.out, columnCombo);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1141,25 +1163,8 @@ public abstract class AutoAnalyser extends JFrame
|
|||
calcContinuous.initialise();
|
||||
}
|
||||
|
||||
// Set observations
|
||||
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE)) {
|
||||
calcDiscrete.addObservations(
|
||||
MatrixUtils.selectColumn(dataDiscrete, sourceColumn),
|
||||
MatrixUtils.selectColumn(dataDiscrete, destColumn));
|
||||
} else {
|
||||
// TODO We should be able to directly call setObservations(double[], double[])
|
||||
// here but we can't right now because ChannelCalculator does not
|
||||
// define this method. It would be complicated to fix this
|
||||
// because it involves Conditional MI calculator it seems.
|
||||
// Revisit this later -- for now fix by deferring to child classes
|
||||
// calcContinuous.setObservations(
|
||||
// MatrixUtils.selectColumn(data, sourceColumn),
|
||||
// MatrixUtils.selectColumn(data, destColumn));
|
||||
setObservations(calcContinuous,
|
||||
MatrixUtils.selectColumn(data, sourceColumn),
|
||||
MatrixUtils.selectColumn(data, destColumn));
|
||||
}
|
||||
|
||||
setObservations(calcDiscrete, calcContinuous, columnCombo);
|
||||
|
||||
// Compute the result:
|
||||
double result;
|
||||
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE)) {
|
||||
|
|
@ -1189,11 +1194,15 @@ public abstract class AutoAnalyser extends JFrame
|
|||
} else {
|
||||
// permutation test of statistical significance:
|
||||
EmpiricalMeasurementDistribution measDist;
|
||||
EmpiricalNullDistributionComputer empiricalNullDistCalc;
|
||||
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE)) {
|
||||
measDist = calcDiscrete.computeSignificance(numPermutationsToCheck);
|
||||
empiricalNullDistCalc =
|
||||
(EmpiricalNullDistributionComputer) calcDiscrete;
|
||||
} else {
|
||||
measDist = calcContinuous.computeSignificance(numPermutationsToCheck);
|
||||
empiricalNullDistCalc =
|
||||
(EmpiricalNullDistributionComputer) calcContinuous;
|
||||
}
|
||||
measDist = empiricalNullDistCalc.computeSignificance(numPermutationsToCheck);
|
||||
resultsSuffixStringFormatted = String.format(
|
||||
resultsSuffixString,
|
||||
measDist.getMeanOfDistribution(),
|
||||
|
|
@ -1204,11 +1213,16 @@ public abstract class AutoAnalyser extends JFrame
|
|||
}
|
||||
|
||||
String resultsText;
|
||||
if (sourceDestPairs.size() > 1) {
|
||||
if (variableCombinations.size() > 1) {
|
||||
// We're doing all pairs
|
||||
resultsText = String.format(
|
||||
resultsPrefixString + "%.4f %s" + resultsSuffixStringFormatted,
|
||||
sourceColumn, destColumn, result, units);
|
||||
// OLD:
|
||||
// resultsText = String.format(
|
||||
// resultsPrefixString + "%.4f %s" + resultsSuffixStringFormatted,
|
||||
// sourceColumn, destColumn, result, units);
|
||||
// NEW:
|
||||
resultsText = String.format(formatStringWithColumnNumbers(
|
||||
resultsPrefixString + "%%.4f %%s" + resultsSuffixStringFormatted,
|
||||
columnCombo), result, units);
|
||||
} else {
|
||||
resultsText = String.format(
|
||||
resultsPrefixString + "%.4f %s" + resultsSuffixStringFormatted,
|
||||
|
|
@ -1219,7 +1233,7 @@ public abstract class AutoAnalyser extends JFrame
|
|||
System.out.println(resultsText);
|
||||
}
|
||||
|
||||
if ((sourceDestPairs.size() == 1) &&
|
||||
if ((variableCombinations.size() == 1) &&
|
||||
!selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE)) {
|
||||
// Read the current property values back out (in case of
|
||||
// automated parameter assignment)
|
||||
|
|
@ -1249,11 +1263,64 @@ public abstract class AutoAnalyser extends JFrame
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to allow child to fill out what all of the variable combinations would be that
|
||||
* would be evaluated by this measure
|
||||
*
|
||||
* @param variableCombinations
|
||||
*/
|
||||
protected abstract void fillOutAllCombinations(Vector<int[]> variableCombinations);
|
||||
|
||||
/**
|
||||
* Method to allow child classes to set up the loops over all combinations of
|
||||
* columns
|
||||
*
|
||||
* @param javaCode
|
||||
* @param pythonCode
|
||||
* @param matlabCode
|
||||
* @return A string array with the names used for the variables iterating over
|
||||
* each column
|
||||
*/
|
||||
protected abstract String[] setUpLoopsForAllCombos(StringBuffer javaCode,
|
||||
StringBuffer pythonCode, StringBuffer matlabCode);
|
||||
|
||||
/**
|
||||
* Method to allow child classes to finalise the loops over all combinations of
|
||||
* columns
|
||||
*
|
||||
* @param javaCode
|
||||
* @param pythonCode
|
||||
* @param matlabCode
|
||||
*/
|
||||
protected abstract void finaliseLoopsForAllCombos(StringBuffer javaCode,
|
||||
StringBuffer pythonCode, StringBuffer matlabCode);
|
||||
|
||||
/**
|
||||
* Method to allow child classes to format a string with
|
||||
* an array of ints for the column numbers (since the number
|
||||
* of these is variable, it's easier if the child classes do this)
|
||||
*
|
||||
* @param columnNumbers array of column numbers used to identify the variables.
|
||||
* @return
|
||||
*/
|
||||
protected abstract String formatStringWithColumnNumbers(String formatStr, int[] columnNumbers);
|
||||
|
||||
/**
|
||||
* Check whether this measure type should skip this particular
|
||||
* combination of columns or not
|
||||
* (e.g. for a pairwise measurement we do want to skip
|
||||
* where the two columns are equal).
|
||||
*
|
||||
* @param columnCombo
|
||||
* @return
|
||||
*/
|
||||
protected abstract boolean skipColumnCombo(int[] columnCombo);
|
||||
|
||||
/**
|
||||
* Method to assign and initialise our continuous calculator class
|
||||
* @throws Exception
|
||||
*/
|
||||
protected abstract ChannelCalculatorCommon assignCalcObjectContinuous(String selectedCalcType) throws Exception;
|
||||
protected abstract InfoMeasureCalculatorContinuous assignCalcObjectContinuous(String selectedCalcType) throws Exception;
|
||||
|
||||
/**
|
||||
* Method to assign and initialise our discrete calculator class
|
||||
|
|
@ -1269,11 +1336,11 @@ public abstract class AutoAnalyser extends JFrame
|
|||
*
|
||||
*/
|
||||
protected class DiscreteCalcAndArguments {
|
||||
ChannelCalculatorDiscrete calc;
|
||||
InfoMeasureCalculatorDiscrete calc;
|
||||
int base;
|
||||
String arguments;
|
||||
|
||||
DiscreteCalcAndArguments(ChannelCalculatorDiscrete calc, int base,
|
||||
DiscreteCalcAndArguments(InfoMeasureCalculatorDiscrete calc, int base,
|
||||
String arguments) {
|
||||
this.calc = calc;
|
||||
this.base = base;
|
||||
|
|
@ -1281,16 +1348,17 @@ public abstract class AutoAnalyser extends JFrame
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Method to set the observations on the underlying calculator
|
||||
*
|
||||
* @param calc
|
||||
* @param source
|
||||
* @param dest
|
||||
* @param calcDiscrete
|
||||
* @param calcContinuous
|
||||
* @param columnCombo int array for the columns of data being computed with.
|
||||
* @throws Exception
|
||||
*/
|
||||
protected abstract void setObservations(ChannelCalculatorCommon calc,
|
||||
double[] source, double[] dest) throws Exception;
|
||||
protected abstract void setObservations(InfoMeasureCalculatorDiscrete calcDiscrete,
|
||||
InfoMeasureCalculatorContinuous calcContinuous,
|
||||
int[] columnCombo) throws Exception;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -1417,45 +1485,23 @@ public abstract class AutoAnalyser extends JFrame
|
|||
System.out.println("Getting calc properties");
|
||||
String selectedCalcType = (String)
|
||||
calcTypeComboBox.getSelectedItem();
|
||||
String[] classSpecificPropertyNames = null;
|
||||
String[] classSpecificPropertiesFieldNames = null;
|
||||
String[] classSpecificPropertyDescriptions = null;
|
||||
ChannelCalculatorCommon calc = null;
|
||||
CalcProperties calcProperties = null;
|
||||
try {
|
||||
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE)) {
|
||||
calcClass = discreteClass;
|
||||
calc = null; // Not used
|
||||
classSpecificPropertyNames = discreteProperties;
|
||||
classSpecificPropertiesFieldNames = null; // Not used
|
||||
classSpecificPropertyDescriptions = discretePropertyDescriptions;
|
||||
} else {
|
||||
calc = assignCalcObjectContinuous(selectedCalcType);
|
||||
calcClass = calc.getClass();
|
||||
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_GAUSSIAN)) {
|
||||
classSpecificPropertyNames = gaussianProperties;
|
||||
classSpecificPropertiesFieldNames = gaussianPropertiesFieldNames;
|
||||
classSpecificPropertyDescriptions = gaussianPropertyDescriptions;
|
||||
} else if (selectedCalcType.startsWith(CALC_TYPE_KRASKOV)) {
|
||||
// The if statement will work for both MI Kraskov calculators
|
||||
classSpecificPropertyNames = kraskovProperties;
|
||||
classSpecificPropertiesFieldNames = kraskovPropertiesFieldNames;
|
||||
classSpecificPropertyDescriptions = kraskovPropertyDescriptions;
|
||||
} else if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_KERNEL)) {
|
||||
classSpecificPropertyNames = kernelProperties;
|
||||
classSpecificPropertiesFieldNames = kernelPropertiesFieldNames;
|
||||
classSpecificPropertyDescriptions = kernelPropertyDescriptions;
|
||||
} else {
|
||||
calcClass = null;
|
||||
throw new Exception("No recognised calculator selected: " +
|
||||
selectedCalcType);
|
||||
}
|
||||
}
|
||||
calcProperties = assignCalcProperties(selectedCalcType);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace(System.err);
|
||||
JOptionPane.showMessageDialog(this,
|
||||
ex.getMessage());
|
||||
resultsLabel.setText("Cannot load requested calculator");
|
||||
}
|
||||
String[] classSpecificPropertyNames =
|
||||
calcProperties.classSpecificPropertyNames;
|
||||
String[] classSpecificPropertiesFieldNames =
|
||||
calcProperties.classSpecificPropertiesFieldNames;
|
||||
String[] classSpecificPropertyDescriptions =
|
||||
calcProperties.classSpecificPropertyDescriptions;
|
||||
calcClass = calcProperties.calcClass;
|
||||
Object calc = calcProperties.calc;
|
||||
|
||||
// Now get all of the possible properties for this class:
|
||||
propertyNames = new Vector<String>();
|
||||
|
|
@ -1513,20 +1559,65 @@ public abstract class AutoAnalyser extends JFrame
|
|||
// Now extract the default values for all of these properties:
|
||||
propertyValues = new HashMap<String,String>();
|
||||
for (String propName : propertyNames) {
|
||||
String defaultPropValue = null;
|
||||
try {
|
||||
defaultPropValue = calc.getProperty(propName);
|
||||
InfoMeasureCalculatorContinuous calcCont =
|
||||
(InfoMeasureCalculatorContinuous) calc;
|
||||
String propValue = calcCont.getProperty(propName);
|
||||
propertyValues.put(propName, propValue);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace(System.err);
|
||||
JOptionPane.showMessageDialog(this,
|
||||
ex.getMessage());
|
||||
propertyValues.put(propName, "Cannot find a value");
|
||||
}
|
||||
propertyValues.put(propName, defaultPropValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Structure to return calculator properties
|
||||
*
|
||||
* @author Joseph Lizier
|
||||
*
|
||||
*/
|
||||
protected class CalcProperties {
|
||||
// An default instantiation of the required calculator object
|
||||
// for continuous data (this is not used for discrete)
|
||||
InfoMeasureCalculatorContinuous calc;
|
||||
// Class of the required calculator
|
||||
@SuppressWarnings("rawtypes")
|
||||
Class calcClass;
|
||||
String[] classSpecificPropertyNames;
|
||||
String[] classSpecificPropertiesFieldNames;
|
||||
String[] classSpecificPropertyDescriptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign the property details for the calculator in use.
|
||||
* Should be overridden by child classes, though they
|
||||
* can refer here to handle discrete calculators.
|
||||
*
|
||||
* @param selectedCalcType String name of the calculator
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
protected CalcProperties assignCalcProperties(String selectedCalcType)
|
||||
throws Exception {
|
||||
|
||||
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE)) {
|
||||
CalcProperties calcProperties = new CalcProperties();
|
||||
calcProperties.calcClass = discreteClass;
|
||||
calcProperties.calc = null; // Not used
|
||||
calcProperties.classSpecificPropertyNames = discreteProperties;
|
||||
calcProperties.classSpecificPropertiesFieldNames = null; // Not used
|
||||
calcProperties.classSpecificPropertyDescriptions = discretePropertyDescriptions;
|
||||
return calcProperties;
|
||||
} else {
|
||||
// We don't handle any other calculators here
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
// Source or dest col number updated
|
||||
|
|
@ -1594,21 +1685,16 @@ public abstract class AutoAnalyser extends JFrame
|
|||
// so we'll just act on potential changes from both.
|
||||
// This won't cause a problem here
|
||||
|
||||
if (e.getSource() == allPairsCheckBox) {
|
||||
if (e.getSource() == allCombosCheckBox) {
|
||||
// "All pairs" checkbox -- update in case changed:
|
||||
if (allPairsCheckBox.isSelected()) {
|
||||
sourceColTextField.setEnabled(false);
|
||||
destColTextField.setEnabled(false);
|
||||
if (allCombosCheckBox.isSelected()) {
|
||||
for (int i = 0; i < numVariables; i++) {
|
||||
variableColTextFields[i].setEnabled(false);
|
||||
}
|
||||
} else {
|
||||
sourceColTextField.setEnabled(true);
|
||||
destColTextField.setEnabled(true);
|
||||
}
|
||||
} else if (e.getSource() == computeResultCheckBox) {
|
||||
// Compute checkbox -- update in case changed:
|
||||
if (computeResultCheckBox.isSelected()) {
|
||||
computeButton.setText(buttonTextCodeAndCompute);
|
||||
} else {
|
||||
computeButton.setText(buttonTextCodeOnly);
|
||||
for (int i = 0; i < numVariables; i++) {
|
||||
variableColTextFields[i].setEnabled(true);
|
||||
}
|
||||
}
|
||||
} else if (e.getSource() == statSigCheckBox) {
|
||||
System.out.println("StatSigCheckBox state changed to " + statSigCheckBox.isSelected());
|
||||
|
|
@ -1626,9 +1712,16 @@ public abstract class AutoAnalyser extends JFrame
|
|||
statSigAnalyticCheckBox.setSelected(false);
|
||||
statSigAnalyticCheckBox.setEnabled(false);
|
||||
}
|
||||
} else if (e.getSource() == computeResultCheckBox) {
|
||||
// Compute checkbox -- update in case changed:
|
||||
if (computeResultCheckBox.isSelected()) {
|
||||
computeButton.setText(buttonTextCodeAndCompute);
|
||||
} else {
|
||||
computeButton.setText(buttonTextCodeOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether the current calculator class implements the
|
||||
* AnalyticNullDistributionComputer interface
|
||||
|
|
|
|||
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package infodynamics.demos.autoanalysis;
|
||||
|
||||
import infodynamics.measures.continuous.ChannelCalculator;
|
||||
import infodynamics.measures.continuous.InfoMeasureCalculatorContinuous;
|
||||
import infodynamics.measures.discrete.ChannelCalculatorDiscrete;
|
||||
import infodynamics.measures.discrete.InfoMeasureCalculatorDiscrete;
|
||||
import infodynamics.utils.MatrixUtils;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* This abstract class provides a GUI to build a simple calculation
|
||||
* over a source-target channel,
|
||||
* and supply the code to execute it.
|
||||
* Child classes fix this to a TE or MI calculation.
|
||||
*
|
||||
*
|
||||
* @author Joseph Lizier
|
||||
*
|
||||
*/
|
||||
public abstract class AutoAnalyserChannelCalculator extends AutoAnalyser {
|
||||
|
||||
/**
|
||||
* Need serialVersionUID to be serializable
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// Property names for specific continuous calculators:
|
||||
protected String[] gaussianProperties;
|
||||
protected String[] gaussianPropertiesFieldNames;
|
||||
protected String[] gaussianPropertyDescriptions;
|
||||
protected String[] kernelProperties;
|
||||
protected String[] kernelPropertiesFieldNames;
|
||||
protected String[] kernelPropertyDescriptions;
|
||||
protected String[] kraskovProperties;
|
||||
protected String[] kraskovPropertiesFieldNames;
|
||||
protected String[] kraskovPropertyDescriptions;
|
||||
|
||||
/**
|
||||
* Constructor to initialise the GUI for a channel calculator
|
||||
*/
|
||||
protected void makeSpecificInitialisations() {
|
||||
numVariables = 2;
|
||||
variableColNumLabels = new String[] {"Source", "Destination"};
|
||||
useAllCombosCheckBox = true;
|
||||
useStatSigCheckBox = true;
|
||||
wordForCombinations = "pairs";
|
||||
variableRelationshipFormatString = "col_%d -> col_%d";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fillOutAllCombinations(Vector<int[]> variableCombinations) {
|
||||
// All combinations here means all pairs
|
||||
for (int s = 0; s < dataColumns; s++) {
|
||||
for (int d = 0; d < dataColumns; d++) {
|
||||
variableCombinations.add(new int[] {s, d});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] setUpLoopsForAllCombos(StringBuffer javaCode,
|
||||
StringBuffer pythonCode, StringBuffer matlabCode) {
|
||||
// Set up loops in the code:
|
||||
// 1. Java code
|
||||
javaCode.append(" \n");
|
||||
javaCode.append(" // Compute for all pairs:\n");
|
||||
javaCode.append(" for (int s = 0; s < " + dataColumns +
|
||||
"; s++) {\n");
|
||||
javaCode.append(" for (int d = 0; d < " + dataColumns +
|
||||
"; d++) {\n");
|
||||
String javaPrefix = " ";
|
||||
javaCode.append(javaPrefix + "// For each source-dest pair:\n");
|
||||
javaCode.append(javaPrefix + "if (s == d) {\n");
|
||||
javaCode.append(javaPrefix + " continue;\n");
|
||||
javaCode.append(javaPrefix + "}\n");
|
||||
// 2. Python code
|
||||
pythonCode.append("\n");
|
||||
pythonCode.append("# Compute for all pairs:\n");
|
||||
pythonCode.append("for s in range(" + dataColumns + "):\n");
|
||||
pythonCode.append("\tfor d in range(" + dataColumns + "):\n");
|
||||
String pythonPrefix = "\t\t";
|
||||
pythonCode.append(pythonPrefix+ "# For each source-dest pair:\n");
|
||||
pythonCode.append(pythonPrefix + "if (s == d):\n");
|
||||
pythonCode.append(pythonPrefix + "\tcontinue\n");
|
||||
// 3. Matlab code
|
||||
matlabCode.append("\n");
|
||||
matlabCode.append("% Compute for all pairs:\n");
|
||||
matlabCode.append("for s = 1:" + dataColumns + "\n");
|
||||
matlabCode.append("\tfor d = 1:" + dataColumns + "\n");
|
||||
String matlabPrefix = "\t\t";
|
||||
matlabCode.append(matlabPrefix + "% For each source-dest pair:\n");
|
||||
matlabCode.append(matlabPrefix + "if (s == d)\n");
|
||||
matlabCode.append(matlabPrefix + "\tcontinue;\n");
|
||||
matlabCode.append(matlabPrefix + "end\n");
|
||||
|
||||
// Return the variables to index each column:
|
||||
return new String[] {"s", "d"};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finaliseLoopsForAllCombos(StringBuffer javaCode,
|
||||
StringBuffer pythonCode, StringBuffer matlabCode) {
|
||||
|
||||
// 1. Java code
|
||||
javaCode.append(" }\n");
|
||||
javaCode.append(" }\n");
|
||||
// 2. Python code
|
||||
// Nothing to do
|
||||
// 3. Matlab code
|
||||
matlabCode.append("\tend\n");
|
||||
matlabCode.append("end\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String formatStringWithColumnNumbers(String formatStr, int[] columnNumbers) {
|
||||
// We format the source and target variable numbers into the
|
||||
// return string here:
|
||||
return String.format(formatStr,
|
||||
columnNumbers[0], columnNumbers[1]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean skipColumnCombo(int[] columnCombo) {
|
||||
if (columnCombo[0] == columnCombo[1]) {
|
||||
// source and destination columns are the same here,
|
||||
// so don't compute the channel measure
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setObservations(InfoMeasureCalculatorDiscrete calcDiscrete,
|
||||
InfoMeasureCalculatorContinuous calcContinuous,
|
||||
int[] columnCombo) throws Exception {
|
||||
|
||||
String selectedCalcType = (String)
|
||||
calcTypeComboBox.getSelectedItem();
|
||||
|
||||
int sourceColumn = columnCombo[0];
|
||||
int destColumn = columnCombo[1];
|
||||
|
||||
// Set observations
|
||||
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_DISCRETE)) {
|
||||
ChannelCalculatorDiscrete cc = (ChannelCalculatorDiscrete) calcDiscrete;
|
||||
cc.addObservations(
|
||||
MatrixUtils.selectColumn(dataDiscrete, sourceColumn),
|
||||
MatrixUtils.selectColumn(dataDiscrete, destColumn));
|
||||
} else {
|
||||
ChannelCalculator cc = (ChannelCalculator) calcContinuous;
|
||||
cc.setObservations(
|
||||
MatrixUtils.selectColumn(data, sourceColumn),
|
||||
MatrixUtils.selectColumn(data, destColumn));
|
||||
}
|
||||
}
|
||||
|
||||
protected CalcProperties assignCalcProperties(String selectedCalcType)
|
||||
throws Exception {
|
||||
// Let the super class handle discrete calculators
|
||||
CalcProperties calcProperties = super.assignCalcProperties(selectedCalcType);
|
||||
if (calcProperties == null) {
|
||||
// We need to assign properties for a continuous calculator
|
||||
calcProperties = new CalcProperties();
|
||||
calcProperties.calc = assignCalcObjectContinuous(selectedCalcType);
|
||||
calcProperties.calcClass = calcProperties.calc.getClass();
|
||||
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_GAUSSIAN)) {
|
||||
calcProperties.classSpecificPropertyNames = gaussianProperties;
|
||||
calcProperties.classSpecificPropertiesFieldNames = gaussianPropertiesFieldNames;
|
||||
calcProperties.classSpecificPropertyDescriptions = gaussianPropertyDescriptions;
|
||||
} 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;
|
||||
} else if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_KERNEL)) {
|
||||
calcProperties.classSpecificPropertyNames = kernelProperties;
|
||||
calcProperties.classSpecificPropertiesFieldNames = kernelPropertiesFieldNames;
|
||||
calcProperties.classSpecificPropertyDescriptions = kernelPropertyDescriptions;
|
||||
} else {
|
||||
calcProperties = null;
|
||||
throw new Exception("No recognised calculator selected: " +
|
||||
selectedCalcType);
|
||||
}
|
||||
}
|
||||
return calcProperties;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
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;
|
||||
|
|
@ -41,7 +40,7 @@ import java.awt.event.MouseListener;
|
|||
* @author Joseph Lizier
|
||||
*
|
||||
*/
|
||||
public class AutoAnalyserMI extends AutoAnalyser
|
||||
public class AutoAnalyserMI extends AutoAnalyserChannelCalculator
|
||||
implements ActionListener, DocumentListener, MouseListener {
|
||||
|
||||
/**
|
||||
|
|
@ -59,6 +58,8 @@ public class AutoAnalyserMI extends AutoAnalyser
|
|||
*/
|
||||
protected void makeSpecificInitialisations() {
|
||||
|
||||
super.makeSpecificInitialisations();
|
||||
|
||||
// Set up the properties for MI:
|
||||
measureAcronym = "MI";
|
||||
appletTitle = "JIDT Mutual Information Auto-Analyser";
|
||||
|
|
@ -159,7 +160,8 @@ public class AutoAnalyserMI extends AutoAnalyser
|
|||
/**
|
||||
* Method to assign and initialise our continuous calculator class
|
||||
*/
|
||||
protected ChannelCalculatorCommon assignCalcObjectContinuous(String selectedCalcType) throws Exception {
|
||||
@Override
|
||||
protected MutualInfoCalculatorMultiVariate assignCalcObjectContinuous(String selectedCalcType) throws Exception {
|
||||
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_GAUSSIAN)) {
|
||||
return new MutualInfoCalculatorMultiVariateGaussian();
|
||||
} else if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_KRASKOV_ALG1)) {
|
||||
|
|
@ -205,13 +207,6 @@ public class AutoAnalyserMI extends AutoAnalyser
|
|||
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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
package infodynamics.demos.autoanalysis;
|
||||
|
||||
import infodynamics.measures.continuous.ChannelCalculatorCommon;
|
||||
import infodynamics.measures.continuous.ConditionalMutualInfoMultiVariateCommon;
|
||||
import infodynamics.measures.continuous.TransferEntropyCalculator;
|
||||
import infodynamics.measures.continuous.gaussian.TransferEntropyCalculatorGaussian;
|
||||
|
|
@ -41,7 +40,7 @@ import java.awt.event.MouseListener;
|
|||
* @author Joseph Lizier
|
||||
*
|
||||
*/
|
||||
public class AutoAnalyserTE extends AutoAnalyser
|
||||
public class AutoAnalyserTE extends AutoAnalyserChannelCalculator
|
||||
implements ActionListener, DocumentListener, MouseListener {
|
||||
|
||||
/**
|
||||
|
|
@ -60,10 +59,17 @@ public class AutoAnalyserTE extends AutoAnalyser
|
|||
*/
|
||||
protected void makeSpecificInitialisations() {
|
||||
|
||||
super.makeSpecificInitialisations();
|
||||
|
||||
// Set up the properties for TE:
|
||||
measureAcronym = "TE";
|
||||
appletTitle = "JIDT Transfer Entropy Auto-Analyser";
|
||||
|
||||
calcTypes = new String[] {
|
||||
CALC_TYPE_DISCRETE, CALC_TYPE_GAUSSIAN,
|
||||
CALC_TYPE_KRASKOV, CALC_TYPE_KERNEL};
|
||||
unitsForEachCalc = new String[] {"bits", "nats", "nats", "bits"};
|
||||
|
||||
// Discrete:
|
||||
discreteClass = TransferEntropyCalculatorDiscrete.class;
|
||||
discreteProperties = new String[] {
|
||||
|
|
@ -214,7 +220,7 @@ public class AutoAnalyserTE extends AutoAnalyser
|
|||
/**
|
||||
* Method to assign and initialise our continuous calculator class
|
||||
*/
|
||||
protected ChannelCalculatorCommon assignCalcObjectContinuous(String selectedCalcType) throws Exception {
|
||||
protected TransferEntropyCalculator assignCalcObjectContinuous(String selectedCalcType) throws Exception {
|
||||
if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_GAUSSIAN)) {
|
||||
return new TransferEntropyCalculatorGaussian();
|
||||
} else if (selectedCalcType.equalsIgnoreCase(CALC_TYPE_KRASKOV)) {
|
||||
|
|
@ -294,13 +300,6 @@ public class AutoAnalyserTE extends AutoAnalyser
|
|||
base + ", " + k + ", " + k_tau + ", " + l + ", " + l_tau + ", " + delay);
|
||||
}
|
||||
|
||||
protected void setObservations(ChannelCalculatorCommon calc,
|
||||
double[] source, double[] dest) throws Exception {
|
||||
// We know this is a TransferEntropyCalculator
|
||||
TransferEntropyCalculator teCalc = (TransferEntropyCalculator) calc;
|
||||
teCalc.setObservations(source, dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param args
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue