All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.cmu.tetradapp.editor.IndependenceFactsEditor Maven / Gradle / Ivy

The newest version!
///////////////////////////////////////////////////////////////////////////////
// For information as to what this class does, see the Javadoc, below.       //
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,       //
// 2007, 2008, 2009, 2010, 2014, 2015, 2022 by Peter Spirtes, Richard        //
// Scheines, Joseph Ramsey, and Clark Glymour.                               //
//                                                                           //
// 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 2 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, write to the Free Software               //
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA //
///////////////////////////////////////////////////////////////////////////////

package edu.cmu.tetradapp.editor;

import edu.cmu.tetrad.graph.Node;
import edu.cmu.tetrad.search.IndependenceTest;
import edu.cmu.tetrad.search.test.IndependenceResult;
import edu.cmu.tetrad.search.test.MsepTest;
import edu.cmu.tetrad.util.ChoiceGenerator;
import edu.cmu.tetrad.util.SublistGenerator;
import edu.cmu.tetradapp.model.IndTestModel;
import edu.cmu.tetradapp.model.IndTestProducer;
import edu.cmu.tetradapp.model.IndependenceResultIndFacts;
import edu.cmu.tetradapp.util.IntTextField;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.List;
import java.util.*;
import java.util.prefs.Preferences;


/**
 * Lists independence facts specified by user and allows the list to be sorted by independence fact or by p value.
 *
 * @author josephramsey
 * @version $Id: $Id
 */
public class IndependenceFactsEditor extends JPanel {

    /**
     * The number format.
     */
    private final NumberFormat nf = new DecimalFormat("0.0000");

    /**
     * The independence test model.
     */
    private IndTestModel model;

    /**
     * The independence test producers.
     */
    private LinkedList vars;

    /**
     * The text field.
     */
    private JTextField textField;

    /**
     * The independence test producers.
     */
    private List indTestProducers;

    /**
     * The results.
     */
    private List> results = new ArrayList<>();

    /**
     * The table model.
     */
    private AbstractTableModel tableModel;

    /**
     * The sort direction.
     */
    private int sortDir;

    /**
     * The last sort column.
     */
    private int lastSortCol;

    /**
     * Whether to show p values.
     */
    private boolean showPs;

    /**
     * 

Constructor for IndependenceFactsEditor.

* * @param model a {@link edu.cmu.tetradapp.model.IndTestModel} object */ public IndependenceFactsEditor(IndTestModel model) { this.indTestProducers = model.getIndTestProducers(); this.model = model; this.vars = new LinkedList<>(); this.textField = new JTextField(40); this.textField.setEditable(false); this.textField.setFont(new Font("Serif", Font.BOLD, 14)); this.textField.setBackground(new Color(250, 250, 250)); this.vars = model.getVars(); this.results = model.getResults(); if (this.results == null) { this.results = new ArrayList<>(); } resetText(); if (this.indTestProducers.isEmpty()) { throw new IllegalArgumentException("At least one source must be specified"); } List names = this.indTestProducers.get(0).getIndependenceTest().getVariableNames(); for (int i = 1; i < this.indTestProducers.size(); i++) { List _names = this.indTestProducers.get(i).getIndependenceTest().getVariableNames(); if (!new HashSet<>(names).equals(new HashSet<>(_names))) { throw new IllegalArgumentException("All sources must have the same variable names."); } } buildGui(); } //========================PUBLIC METHODS==========================// /** *

Constructor for IndependenceFactsEditor.

* * @param layout a {@link java.awt.LayoutManager} object * @param isDoubleBuffered a boolean */ public IndependenceFactsEditor(LayoutManager layout, boolean isDoubleBuffered) { super(layout, isDoubleBuffered); } //=============================PRIVATE METHODS=======================// private static List asList(int[] indices, List nodes) { List list = new LinkedList<>(); for (int i : indices) { list.add(nodes.get(i)); } return list; } private static String factString(Node x, Node y, Set condSet) { StringBuilder sb = new StringBuilder(); sb.append(x.getName()); sb.append(" _||_ "); sb.append(y.getName()); Iterator it = condSet.iterator(); if (it.hasNext()) { sb.append(" | "); sb.append(it.next()); } while (it.hasNext()) { sb.append(", "); sb.append(it.next()); } return sb.toString(); } /** * Performs the action of opening a session from a file. */ private void buildGui() { // this.independenceTest = getIndTestProducer().getIndependenceTest(); List varNames = new ArrayList<>(); varNames.add("VAR"); varNames.addAll(getDataVars()); varNames.add("?"); varNames.add("+"); JComboBox variableBox = new JComboBox<>(); DefaultComboBoxModel aModel1 = new DefaultComboBoxModel<>(varNames.toArray(new String[0])); aModel1.setSelectedItem("VAR"); variableBox.setModel(aModel1); variableBox.addActionListener(e -> { JComboBox box = (JComboBox) e.getSource(); String var = (String) box.getSelectedItem(); LinkedList vars = getVars(); int size = vars.size(); if ("VAR".equals(var)) { return; } if ("?".equals(var)) { if (!vars.contains("+")) { vars.addLast(var); } } else if ("+".equals(var)) { if (size >= 2) { vars.addLast(var); } } else if ((vars.indexOf("?") < 2) && !(vars.contains("+")) && !(vars.contains(var))) { vars.add(var); } resetText(); // This is a workaround to an introduced bug in the JDK whereby // repeated selections of the same item send out just one // action event. DefaultComboBoxModel aModel = new DefaultComboBoxModel<>( varNames.toArray(new String[0])); aModel.setSelectedItem("VAR"); variableBox.setModel(aModel); }); JButton delete = new JButton("Delete"); delete.addActionListener(e -> { if (!getVars().isEmpty()) { getVars().removeLast(); resetText(); } }); this.textField.addKeyListener(new KeyAdapter() { public void keyTyped(KeyEvent e) { if ('?' == e.getKeyChar()) { variableBox.setSelectedItem("?"); } else if ('+' == e.getKeyChar()) { variableBox.setSelectedItem("+"); } else if ('\b' == e.getKeyChar()) { IndependenceFactsEditor.this.vars.removeLast(); resetText(); } e.consume(); } }); delete.addKeyListener(new KeyAdapter() { public void keyTyped(KeyEvent e) { if ('?' == e.getKeyChar()) { variableBox.setSelectedItem("?"); } else if ('+' == e.getKeyChar()) { variableBox.setSelectedItem("+"); } else if ('\b' == e.getKeyChar()) { IndependenceFactsEditor.this.vars.removeLast(); resetText(); } } }); variableBox.addKeyListener(new KeyAdapter() { public void keyTyped(KeyEvent e) { super.keyTyped(e); if ('\b' == e.getKeyChar()) { IndependenceFactsEditor.this.vars.removeLast(); resetText(); } } }); JButton list = new JButton("LIST"); list.setFont(new Font("Dialog", Font.BOLD, 14)); list.addActionListener(e -> generateResults()); Box b1 = Box.createVerticalBox(); Box b2 = Box.createHorizontalBox(); b2.add(new JLabel("Compares conditional independence tests from the given sources: ")); b2.add(Box.createHorizontalGlue()); b1.add(b2); for (int i = 0; i < this.indTestProducers.size(); i++) { Box b2a = Box.createHorizontalBox(); b2a.add(new JLabel(this.indTestProducers.get(i).getName() + ": " + getIndependenceTest(i).toString())); b2a.add(Box.createHorizontalGlue()); b1.add(b2a); } b1.add(Box.createVerticalStrut(5)); Box b3 = Box.createHorizontalBox(); b3.add(getTextField()); b3.add(variableBox); b3.add(delete); b1.add(b3); b1.add(Box.createVerticalStrut(10)); this.tableModel = new AbstractTableModel() { public String getColumnName(int column) { if (column == 0) { return "Index"; } if (column == 1) { return "Fact"; } else if (column >= 2) { return IndependenceFactsEditor.this.indTestProducers.get(column - 2).getName();// "Judgment"; } return null; } public int getColumnCount() { return 2 + IndependenceFactsEditor.this.indTestProducers.size(); } public int getRowCount() { return IndependenceFactsEditor.this.results.size(); } public Object getValueAt(int rowIndex, int columnIndex) { if (rowIndex > IndependenceFactsEditor.this.results.size()) return null; if (columnIndex == 0) { return IndependenceFactsEditor.this.results.get(rowIndex).get(0).getIndex(); } if (columnIndex == 1) { return IndependenceFactsEditor.this.results.get(rowIndex).get(0).getFact(); } IndependenceResultIndFacts independenceResult = IndependenceFactsEditor.this.results.get(rowIndex).get(columnIndex - 2); for (int i = 0; i < IndependenceFactsEditor.this.indTestProducers.size(); i++) { if (columnIndex == i + 2) { if (getIndependenceTest(i) instanceof MsepTest) { if (independenceResult.getType() == IndependenceResultIndFacts.Type.INDEPENDENT) { return "D-SEPARATED"; } else if (independenceResult.getType() == IndependenceResultIndFacts.Type.DEPENDENT) { return "d-connected"; } else if (independenceResult.getType() == IndependenceResultIndFacts.Type.UNDETERMINED) { return "*"; } } else { if (IndependenceFactsEditor.this.isShowPs()) { return nf.format(independenceResult.getpValue()); } else { if (independenceResult.getType() == IndependenceResultIndFacts.Type.INDEPENDENT) { return "INDEPENDENT"; } else if (independenceResult.getType() == IndependenceResultIndFacts.Type.DEPENDENT) { return "dependent"; } else if (independenceResult.getType() == IndependenceResultIndFacts.Type.UNDETERMINED) { return "*"; } } } } } return null; } public Class getColumnClass(int columnIndex) { if (columnIndex == 0) { return Number.class; } if (columnIndex == 1) { return String.class; } else if (columnIndex == 2) { return Number.class; } else { return Number.class; } } }; JTable table = new JTable(tableModel); table.getColumnModel().getColumn(0).setMinWidth(40); table.getColumnModel().getColumn(0).setMaxWidth(40); table.getColumnModel().getColumn(1).setMinWidth(200); table.getColumnModel().getColumn(1).setCellRenderer(new Renderer(this)); for (int i = 2; i < table.getColumnModel().getColumnCount(); i++) { table.getColumnModel().getColumn(i).setMinWidth(100); table.getColumnModel().getColumn(i).setMaxWidth(100); table.getColumnModel().getColumn(i).setCellRenderer(new Renderer(this)); } JTableHeader header = table.getTableHeader(); header.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { JTableHeader header = (JTableHeader) e.getSource(); Point point = e.getPoint(); int col = header.columnAtPoint(point); int sortCol = header.getTable().convertColumnIndexToModel(col); IndependenceFactsEditor.this.sortByColumn(sortCol); } }); JScrollPane scroll = new JScrollPane(table); scroll.setPreferredSize(new Dimension(400, 400)); b1.add(scroll); Box b4 = Box.createHorizontalBox(); b4.add(new JLabel("Limit list to ")); IntTextField field = new IntTextField(this.getListLimit(), 7); field.setFilter((value, oldValue) -> { try { this.setListLimit(value); return value; } catch (Exception e) { return oldValue; } }); b4.add(field); b4.add(new JLabel(" items.")); b4.add(Box.createHorizontalStrut(10)); JButton showPValues = new JButton("Show P Values"); showPValues.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { IndependenceFactsEditor.this.toggleShowPs(); if (showPs) { showPValues.setText("Show Independencies"); } else { showPValues.setText("Show P Values or Scores"); } } }); b4.add(showPValues); b4.add(Box.createHorizontalGlue()); b4.add(list); b1.add(b4); b1.add(Box.createVerticalStrut(10)); JPanel panel = this; panel.setLayout(new BorderLayout()); panel.add(b1, BorderLayout.CENTER); panel.setBorder(new EmptyBorder(10, 10, 10, 10)); } private void sortByColumn(int sortCol) { if (sortCol == this.getLastSortCol()) { this.setSortDir(-1 * this.getSortDir()); } else { this.setSortDir(1); } this.setLastSortCol(sortCol); results.sort((r1, r2) -> { switch (sortCol) { case 0: case 1: return this.getSortDir() * (r1.get(0).getIndex() - r2.get(0).getIndex()); default: int ind1; int ind2; int col = sortCol - 2; if (r1.get(col).getType() == IndependenceResultIndFacts.Type.UNDETERMINED) { ind1 = 0; } else if (r1.get(col).getType() == IndependenceResultIndFacts.Type.DEPENDENT) { ind1 = 1; } else { ind1 = 2; } if (r2.get(col).getType() == IndependenceResultIndFacts.Type.UNDETERMINED) { ind2 = 0; } else if (r2.get(col).getType() == IndependenceResultIndFacts.Type.DEPENDENT) { ind2 = 1; } else { ind2 = 2; } return this.getSortDir() * (ind1 - ind2); } }); tableModel.fireTableDataChanged(); } private boolean isShowPs() { return showPs; } private void toggleShowPs() { showPs = !showPs; tableModel.fireTableDataChanged(); } private List getDataVars() { return this.getIndependenceTest(0).getVariableNames(); } private void resetText() { StringBuilder buf = new StringBuilder(); if (this.getVars().size() == 0) { buf.append("Choose variables and wildcards from dropdown-->"); } if (this.getVars().size() > 0) { buf.append(" ").append(this.getVars().get(0)); buf.append(" _||_ "); } if (this.getVars().size() > 1) { buf.append(this.getVars().get(1)); } if (this.getVars().size() > 2) { buf.append(" | "); } for (int i = 2; i < this.getVars().size() - 1; i++) { buf.append(this.getVars().get(i)); buf.append(", "); } if (this.getVars().size() > 2) { buf.append(this.getVars().get(this.getVars().size() - 1)); } model.setVars(this.getVars()); textField.setText(buf.toString()); } private void generateResults() { results = new ArrayList<>(); List dataVars = this.getDataVars(); if (this.getVars().size() < 2) { tableModel.fireTableDataChanged(); return; } // Need a choice generator over the ?'s, and a depth choice generator over the +'s. The +'s all have to come // at the end at index >= 2. int numQuestionMarksFirstTwo = 0; int numQuestionMarksRest = 0; int numPluses = 0; int numFixed = 0; for (int i = 0; i < vars.size(); i++) { String var = vars.get(i); if ("?".equals(var) && i < 2) numQuestionMarksFirstTwo++; else if ("?".equals(var)) numQuestionMarksRest++; else if ("+".equals(var)) numPluses++; else numFixed++; } int[] questionMarkFirstTwoIndices = new int[numQuestionMarksFirstTwo]; int[] questionMarkRestIndices = new int[numQuestionMarksRest]; int[] plusIndices = new int[numPluses]; int[] fixedIndices = new int[numFixed]; String[] fixedVars = new String[numFixed]; int _i = -1; int _j = -1; int _k = -1; int _l = -1; for (int i = 0; i < vars.size(); i++) { if ("?".equals(vars.get(i)) && i < 2) questionMarkFirstTwoIndices[++_i] = i; else if ("?".equals(vars.get(i))) questionMarkRestIndices[++_j] = i; else if ("+".equals(vars.get(i))) plusIndices[++_k] = i; else { fixedIndices[++_l] = i; fixedVars[_l] = vars.get(i); } } List vars1 = new ArrayList<>(dataVars); vars1.removeAll(vars); ChoiceGenerator gen1 = new ChoiceGenerator(vars1.size(), questionMarkFirstTwoIndices.length); int[] choice1; LOOP: while ((choice1 = gen1.next()) != null) { List s2 = asList(choice1, vars1); List vars2 = new ArrayList<>(vars1); vars2.removeAll(s2); ChoiceGenerator gen2 = new ChoiceGenerator(vars2.size(), questionMarkRestIndices.length); int[] choice2; while ((choice2 = gen2.next()) != null) { List s3 = asList(choice2, vars2); List vars3 = new ArrayList<>(vars2); vars3.removeAll(s3); SublistGenerator gen3 = new SublistGenerator(vars3.size(), plusIndices.length); int[] choice3; while ((choice3 = gen3.next()) != null) { results.add(new ArrayList<>()); for (int prod = 0; prod < indTestProducers.size(); prod++) { String[] vars4 = new String[fixedIndices.length + questionMarkFirstTwoIndices.length + questionMarkRestIndices.length + choice3.length]; for (int i = 0; i < fixedIndices.length; i++) { vars4[fixedIndices[i]] = fixedVars[i]; } for (int i = 0; i < choice1.length; i++) { vars4[questionMarkFirstTwoIndices[i]] = vars1.get(choice1[i]); } for (int i = 0; i < choice2.length; i++) { vars4[questionMarkRestIndices[i]] = vars2.get(choice2[i]); } for (int i = 0; i < choice3.length; i++) { vars4[plusIndices[i]] = vars3.get(choice3[i]); } IndependenceTest independenceTest = this.getIndependenceTest(prod); Node x = independenceTest.getVariable(vars4[0]); Node y = independenceTest.getVariable(vars4[1]); Set z = new HashSet<>(); for (int i = 2; i < vars4.length; i++) { z.add(independenceTest.getVariable(vars4[i])); } IndependenceResultIndFacts.Type indep; double pValue; try { IndependenceResult result = independenceTest.checkIndependence(x, y, z); indep = result.isIndependent() ? IndependenceResultIndFacts.Type.INDEPENDENT : IndependenceResultIndFacts.Type.DEPENDENT; pValue = result.getPValue(); } catch (Exception e) { indep = IndependenceResultIndFacts.Type.UNDETERMINED; pValue = Double.NaN; } this.results.get(this.results.size() - 1).add(new IndependenceResultIndFacts(this.results.size(), IndependenceFactsEditor.factString(x, y, z), indep, pValue)); } if (this.results.size() > getListLimit()) break LOOP; } } } this.model.setResults(this.results); this.tableModel.fireTableDataChanged(); } private LinkedList getVars() { return this.vars; } private JTextField getTextField() { return this.textField; } private IndependenceTest getIndependenceTest(int i) { return this.indTestProducers.get(i).getIndependenceTest(); } private int getLastSortCol() { return this.lastSortCol; } private void setLastSortCol(int lastSortCol) { if (lastSortCol < 0 || lastSortCol > 4) { throw new IllegalArgumentException(); } this.lastSortCol = lastSortCol; } private int getSortDir() { return this.sortDir; } private void setSortDir(int sortDir) { if (!(sortDir == 1 || sortDir == -1)) { throw new IllegalArgumentException(); } this.sortDir = sortDir; } private int getListLimit() { return Preferences.userRoot().getInt("indFactsListLimit", 10000); } private void setListLimit(int listLimit) { if (listLimit < 1) { throw new IllegalArgumentException(); } Preferences.userRoot().putInt("indFactsListLimit", listLimit); } static class Renderer extends DefaultTableCellRenderer { private final IndependenceFactsEditor editor; private JTable table; private int row; private boolean selected; public Renderer(IndependenceFactsEditor editor) { this.editor = editor; } public void setValue(Object value) { int indep = 0; int numCols = table.getModel().getColumnCount(); if (selected) { setForeground(table.getSelectionForeground()); setBackground(table.getSelectionBackground()); } else { for (int i = 2; i < numCols; i++) { Object _value = table.getModel().getValueAt(row, i); if ("INDEPENDENT".equals(_value) || "D-SEPARATED".equals(_value)) { indep++; } } this.setForeground(table.getForeground()); if (!editor.isShowPs()) { if (!(indep == 0 || indep == numCols - 2)) { this.setBackground(Color.YELLOW); } else { this.setBackground(table.getBackground()); } } else { this.setBackground(table.getBackground()); } } this.setText((String) value); } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { this.table = table; this.row = row; selected = isSelected; return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy