package causation.lab; // packages import javax.swing.*; import java.beans.*; import java.io.*; import java.awt.Image; import java.net.*; import java.util.*; import exercise.*; import java.awt.*; import java.awt.event.*; import tetrad.graph.*; import tetrad.model.BayesNetIM; import tetrad.model.BayesNetPM; import tetrad.model.Parameter; // custom classes import causation.lab.LabPanel; import causation.lab.DataTableFrame; import causation.lab.CLExercise; import causation.lab.CLSubmission; import causation.lab.CLEvaluation; import causation.lab.CLEvaluator; /** *

* This is the Applet that runs the CausalityLab. It creates the JFrame * with a JDesktop, and places the various pieces onto the desktop. It * also acts as a router between the LabPanel and the DataTableFrame. * Finally, it performs the evaluations of the user's submissions. *

* Copyright 1999 by David Danks. All rights reserved. *

* * @see LabPanel * @see DataTableFrame * @version 0.9 Sep 1, 1999 * @author David Danks */ public class LabApplet extends JApplet implements PropertyChangeListener { /////////////////// Class Variables /////////////////// protected static String ICON_DIR = "icons/"; // NOTE: DATA_DIR cannot be empty protected static String DEFAULT_DATA_DIR = "data/"; protected static String LOCK_CURSOR = "lockCursor.gif"; protected static String RAND_CURSOR = "randCursor.gif"; protected static String ARROW_CURSOR = "arrowCursor.gif"; protected static String LATENT_CURSOR = "latentCursor.gif"; protected static String CORRECT_RESPONSE = "You got it right!"; protected static String EQUIVALENT_RESPONSE = "Not quite, but your graph is observationally equivalent."; protected static String INCORRECT_RESPONSE = "Sorry, but that is not correct."; protected static Font FONT = new Font("Dialog", Font.BOLD, 14); protected static int DEFAULT_WIDTH = 600; protected static int DEFAULT_HEIGHT = 600; /////////////////// Instance Variables /////////////////// protected JDesktopPane desktop; protected JInternalFrame labIFrame; protected LabPanel lp; protected DataTableFrame dtf; protected Vector dataExpSetup = new Vector(); protected Hashtable dataExpImage = new Hashtable(); protected Hashtable dataDID = new Hashtable(); protected Hashtable iifHash = new Hashtable(); protected CLEvaluator eval = new CLEvaluator(); protected CLExercise exercise; protected String data_dir = DEFAULT_DATA_DIR; /////////////////// Constructors /////////////////// /** * This is a null constructor, in case the Applet gets run as an application */ public LabApplet() { ; } /** * Sets up the CausalityLab when it is run as an Applet */ public void init() { UIManager.put("causation.lab.plaf.WorkbenchUI", "causation.lab.plaf.basic.BasicWorkbenchUI"); UIManager.put("causation.lab.plaf.WBVariableUI", "causation.lab.plaf.basic.BasicWBVariableUI"); UIManager.put("causation.lab.plaf.RandomizerUI", "causation.lab.plaf.basic.BasicRandomizerUI"); UIManager.put("causation.lab.plaf.LatentUI", "causation.lab.plaf.basic.BasicLatentUI"); UIManager.put("causation.lab.plaf.DistributionChooserUI", "causation.lab.plaf.concrete.CDistributionChooserUI"); UIManager.put("stats.plaf.BarChartUI", "stats.plaf.concrete.CBarChartUI"); UIManager.put("stats.plaf.ChartWrapperUI", "stats.plaf.concrete.CChartWrapperUI"); UIManager.put("stats.plaf.LegendUI", "stats.plaf.concrete.CLegendUI"); // check to see if the user wants to have a different data dir String newDir = getParameter("Data directory"); if (newDir != null) data_dir = newDir; // create and show the desktop so we can show a progress bar final JFrame frame = new JFrame("Causality Lab"); desktop = new JDesktopPane(); frame.setContentPane(desktop); frame.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); frame.show(); // Make sure closing the window stops the Applet frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent w) { frame.setVisible(false); frame.dispose(); LabApplet.this.destroy(); } }); // create the progress bar here JInternalFrame prog = new JInternalFrame("Loading lesson...", false, false, false, false); JPanel progPanel = new JPanel(new BorderLayout()); JProgressBar pbar = new JProgressBar(); // find out what BayesNet the user wants, or create the default BayesNetIM bn = null; ObjectInputStream in = null; /* For now, we're just using the default BayesNetIM, since we can't read * in others. At some point, we may want to add a method that lets you * choose from a menu, but we'll stick with this for now. ObjectInputStream in = getBayesNetInputStream(); */ // add the progress bar, since the dialog box is gone progPanel.add(pbar, "Center"); prog.setContentPane(progPanel); desktop.add(prog); Dimension pSize = prog.getPreferredSize(); prog.setBounds((desktop.getSize().width-pSize.width)/2, (desktop.getSize().height-pSize.height)/2, pSize.width, pSize.height); prog.show(); // now read in the appropriate BayesNetIM if (in == null) bn = createDefaultBayesNet(); else { try { bn = (BayesNetIM)(in.readObject()); in.close(); } // just print out the exceptions catch (Exception e) { System.err.println(e); } } pbar.setValue(25); // update the bar // add the initial components lp = new LabPanel(bn, getCodeBase()); lp.addPropertyChangeListener(this); // since we've created the LabPanel, check if we have WBVariable icons WBVariable[] vars = lp.getVariables(); for (int i=0; i 0) // it's finite, so just add to the data table dtf.addDataTable(lp.performExperiment(size), name, im, DataTableFrame.FINITE_DATASET); else { // it's infinite size *= -1; dtf.addDataTable(lp.performExperiment(size), name, im, DataTableFrame.INFINITE_DATASET); size *= -1; // since we'll use size later } // display a (false) progress bar // displayProgressBar(name, size); // de-iconify (if needed), and bring the data table to the front if (dtf.isIcon()) { try { dtf.setIcon(false); } catch (PropertyVetoException pve) { System.out.println("Can't deiconify data display"); } } if (dtf.isShowing()) dtf.show(); else { desktop.add(dtf); dtf.show(); } // store the ExperimentalSetup and DataIndepDisplay ExperimentalSetup exp = new ExperimentalSetup(lp.getWorkbench()); dataExpSetup.addElement(exp); DSeparationFacts dsf = new DSeparationFacts(lp.getTrueManipulatedTetradGraph()); dsf.setFilterAndLockedVars(lp.getOnWorkbenchVariableNames(), lp.getLockedVariableNames()); dataDID.put(exp, new DataIndepDisplay(name, size, dsf)); // check to see if we also need to store the ExpSetupImage for (int i=dataExpSetup.size()-2; i>=0; i--) { ExperimentalSetup key = (ExperimentalSetup)dataExpSetup.elementAt(i); if (key.isEquivalentTo(exp)) return; } dataExpImage.put(exp, lp.getExperimentalSetupImage()); return; } // user changed tabs if (p.getPropertyName().equals("Tab Number")) { return; } // user requested "true" independencies for the given experiment if (p.getPropertyName().equals("Oracle")) { ExperimentalSetup exp = (ExperimentalSetup)dataExpSetup.elementAt (((Integer)p.getNewValue()).intValue()); DataIndepDisplay did = (DataIndepDisplay)dataDID.get(exp); // find the original ES that was used as a key to store the IIF ExperimentalSetup key = null; Enumeration keys = dataExpImage.keys(); while (keys.hasMoreElements()) { key = (ExperimentalSetup)keys.nextElement(); if (key.isEquivalentTo(exp)) break; } IndepInternalFrame iif = getIndepFrame(key); if (iif != null) { // if there is already an IIF, add to it iif.addDataIndeps(did); if (iif.isIcon()) { try { iif.setIcon(false); } catch (PropertyVetoException pve) { System.out.println("Can't deiconify indep display"); } } if (iif.isShowing()) iif.show(); else { desktop.add(iif); iif.show(); } } else { // need to create a new frame Image expImage = (Image)dataExpImage.get(key); iif = new IndepInternalFrame(expImage, did); iifHash.put(key, iif); iif.setOpaque(true); desktop.add(iif); iif.setBounds(0, 0, iif.getPreferredSize().width, iif.getPreferredSize().height); iif.show(); } return; } // user wants to reset the workbench to a particular state if (p.getPropertyName().equals("Reset Workbench")) { lp.loadScreenShot(((Integer)p.getNewValue()).intValue()); return; } // user is submitting their DiGraph if (p.getPropertyName().equals("Submit")) { receiveResults(submitSolution(exercise, new CLSubmission(lp.getUserTetradGraph()))); } if (p.getPropertyName().equals("independence")) { HypIndepDisplay hid = (HypIndepDisplay)p.getNewValue(); if (hid == null) { System.out.println("HypIndepDisplay is null"); return; } ExperimentalSetup exp = (ExperimentalSetup)p.getOldValue(); if (exp == null) { System.out.println("ExperimentalSetup is null"); return; } IndepInternalFrame iif = getIndepFrame(exp); if (iif != null) { hid.setNumber(iif.getNumberHypIndeps()+1); iif.addHypIndeps(hid); if (iif.isIcon()) { try { iif.setIcon(false); } catch (PropertyVetoException pve) { System.out.println("Can't deiconify indep display"); } } if (iif.isShowing()) iif.show(); else { desktop.add(iif); iif.show(); } } else { // need to create a new frame hid.setNumber(1); Image expImage = lp.getExperimentalSetupImage(); iif = new IndepInternalFrame(expImage, hid); iifHash.put(exp, iif); iif.setOpaque(true); desktop.add(iif); iif.setBounds(0, 0, iif.getPreferredSize().width, iif.getPreferredSize().height); iif.show(); return; } } } /** * A helper method for finding the correct indep frame * @param exp The ExperimentalSetup whose IIF we want */ private IndepInternalFrame getIndepFrame(ExperimentalSetup exp) { Enumeration keys = iifHash.keys(); while (keys.hasMoreElements()) { ExperimentalSetup key = (ExperimentalSetup)keys.nextElement(); if (key.isEquivalentTo(exp)) return (IndepInternalFrame)iifHash.get(key); } return null; } // This method would be used if we could generate a progress bar that faked // the construction of data. However, we can't do that right now, so it's // been commented out. /* * A helper method for displaying the dummy progress window * @param name The name of the dataset * @param size The size of the dataset * private void displayProgressBar(String name, int size) { ProgressBarPanel pbp = new ProgressBarPanel(); JInternalFrame frame = new JInternalFrame("Generating data...", true, true, true, true); frame.setContentPane(pbp); desktop.add(frame); frame.setBounds(0, 0, frame.getPreferredSize().width+20, frame.getPreferredSize().height+20); frame.show(); for (int i=0; i<5; i++) { pbp.updateBar(i*20); try { Thread.sleep(1000); } catch (Exception e) { System.out.println(e); } System.out.println("cycle "+i); } pbp.updateBar(100); return; /* JOptionPane.showInternalMessageDialog(this, "Generating data...", "Error!", JOptionPane.ERROR_MESSAGE); // JOptionPane.showInternalMessageDialog(this, panel); System.out.println("break4: labapplet"); /* JInternalFrame jif = new JInternalFrame("Generating data...", true, true, true, true); jif.setContentPane(panel); desktop.add(jif); jif.setBounds(0, 0, jif.getPreferredSize().width, jif.getPreferredSize().height); jif.show(); /* // determine total delay, and increment final int totalTime = 1000 + size*2; final int TOTAL_STEPS = 5; for (int i=0; i Growth <- Sunlight */ private BayesNetIM createDefaultBayesNet() { String[] vars = {"Education", "Income", "Happiness"}; String[][] varVals = { {"High School", "College"}, // Education values {"Low", "Medium", "High"}, // Income values {"Low", "High"} // Happiness values }; String[] edges = {"Education->Income", "Education->Happiness", "Income->Happiness"}; String[][] probs = { {"High School||.7", "College||.3"}, // Education probs {"Low|Education=High School|.6", // Income probs "Medium|Education=High School|.3", "High|Education=High School|.1", "Low|Education=College|.2", "Medium|Education=College|.6", "High|Education=College|.2"}, {"Low|Education=High School;Income=Low|.6", // Happiness probs "High|Education=High School;Income=Low|.4", "Low|Education=High School;Income=Medium|.5", "High|Education=High School;Income=Medium|.5", "Low|Education=High School;Income=High|.4", "High|Education=High School;Income=High|.6", "Low|Education=College;Income=Low|.5", "High|Education=College;Income=Low|.5", "Low|Education=College;Income=Medium|.4", "High|Education=College;Income=Medium|.6", "Low|Education=College;Income=High|.3", "High|Education=College;Income=High|.7", } }; return createBayesNet(vars, varVals, edges, probs); } /** * This is a helper method that creates BayesNetIMs for us. It has a * number of parameters, but this will (in the long run) make it easy * for us to hard code BayesNetIMs into the CausalityLab. This version * of the method randomly assigns probabilities. * @param vars An array of variable names * @param varVals An array of Vectors of variable values * @param edges An array of edge names in the form "FromVar->ToVar" * @return The BayesNetIM for these parameters */ private BayesNetIM createBayesNet(String[] vars, Vector[] varVals, String[] edges) { return createBayesNet(vars, varVals, edges, null); } /** * This is a helper method that creates BayesNetIMs for us. It has a * number of parameters, but this will (in the long run) make it easy * for us to hard code BayesNetIMs into the CausalityLab. This version * of the method randomly assigns probabilities. * @param vars An array of variable names * @param varVals A 2-d String array of variable values * @param edges An array of edge names in the form "FromVar->ToVar" * @return The BayesNetIM for these parameters */ private BayesNetIM createBayesNet(String[] vars, String[][] varVals, String[] edges) { Vector[] valVect = new Vector[varVals.length]; for (int i=0; iToVar" * @param probs A 2-d array of Strings in the following form: * "VAL|par1=val;...;parN=val|PROB", with the array * structured as [var#][prob] * @return The BayesNetIM for these parameters */ private BayesNetIM createBayesNet(String[] vars, String[][] varVals, String[] edges, String[][] probs) { Vector[] valVect = new Vector[varVals.length]; for (int i=0; iToVar" * @param probs A 2-d array of Strings in the following form: * "VAL|par1=val;...;parN=val|PROB", with the array * structured as [var#][prob] * @return The BayesNetIM for these parameters */ private BayesNetIM createBayesNet(String[] vars, Vector[] varVals, String[] edges, String[][] probs) { // construct the DAG DirectedAcyclicGraph dag = new DirectedAcyclicGraph(); for (int i=0; i"); try { dag.addDirectedEdge(st.nextToken(), st.nextToken()); } catch (PropertyVetoException pve) { System.out.println("Can't add edge: "+pve.toString()); return null; } } // now construct the BayesNetPM BayesNetPM bnpm = new BayesNetPM(dag); for (int i=0; inull, if the file doesn't exist, or the user * pressed "cancel". */ private ObjectInputStream getBayesNetInputStream() { ObjectInputStream in = null; // Note that it doesn't matter whether we're local or not, since // Applets can't use Files, they can only use URLs (which we can use // to access local information). URL base = null; try { base = new URL(getCodeBase(), data_dir); } catch (MalformedURLException m) { System.out.println("Bad URL: "+m.toString()); return null; } // now read in the directory, and save the file names to a Vector Vector fileNames = new Vector(); try { InputStream is = base.openStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); while (true) { String line = br.readLine(); if (line == null) break; int cue = line.indexOf("true, if it passes the check; false, * if it fails the check */ protected boolean checkFile(String filename) { // add the checks here String ext = filename.substring(filename.lastIndexOf(".")); if (!ext.equalsIgnoreCase(".dat")) return false; // if it passes all of the checks, just return true; return true; } }