package causation.lab; // Sun packages import java.beans.*; import javax.swing.event.*; import java.util.Iterator; // our packages import tetrad.graph.*; import tetrad.model.*; // custom classes import causation.lab.WorkbenchModelInterface; /** *

* This is the underlying model for the Workbench. It maintains: *

    *
  1. the current Workbench mode *
  2. the current Workbench tool *
  3. the BayesNetIM underlying the Workbench *
  4. the TetradGraph being constructed by the user *
*

* The following PropertyChangeEvents are fired by this class: *

*

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

* * @see Workbench * @see WorkbenchModelInterface * @version 0.9 Feb 26, 1999 * @author David Danks */ public class WorkbenchModel implements WorkbenchModelInterface { /////////////////// Class Variables /////////////////// // mode constants public static final int SETUP_GATHER_MODE = 1000; public static final int HYPOTHESIZE_PREDICT_MODE = 1001; // tool constants public static final int MOVE = 0; public static final int LOCK = 1; public static final int RANDOMIZER = 2; public static final int ARROW = 3; public static final int LATENT = 4; /////////////////// Instance Variables /////////////////// private BayesNetIM bayesNet; private TetradGraph tGraph; private int mode; private int tool; // needed for firing PropertyChangeEvents private EventListenerList listenerList = new EventListenerList(); /////////////////// Constructors /////////////////// /** * Constructs a Workbench in SETUP_GATHER_MODE, with a minimal * BayesNet. */ public WorkbenchModel() { this(null, SETUP_GATHER_MODE); } /** * Constructs a Workbench in SETUP_GATHER_MODE, with the given * BayesNet. * @param bn The underlying BayesNet */ public WorkbenchModel(BayesNetIM bn) { this(bn, SETUP_GATHER_MODE); } /** * Constructs a Workbench in the given mode, with a minimal BayesNet. * @param work_mode The mode to start in */ public WorkbenchModel(int work_mode) { this(null, work_mode); } /** * Constructs a Workbench in the given mode, with the given BayesNetIM. The * other constructors all call this one. Note: you can't set the * user-constructed TetradGraph or the WBVariable array in a constructor, since * these will never be constructed with user changes. Any changes must be * done using the accessor methods. * * @param bn The underlying BayesNetIM * @param work_mode The mode to start in */ public WorkbenchModel(BayesNetIM bn, int work_mode) { // assign the variables bayesNet = bn; mode = work_mode; // check for nulls if (bayesNet == null) bayesNet = createBayesNet(); if ((mode != SETUP_GATHER_MODE) && (mode != HYPOTHESIZE_PREDICT_MODE)) mode = SETUP_GATHER_MODE; // create the DiGraph now (remember that this is what the user creates) tGraph = createTetradGraph(); } /////////////////// Instance Methods /////////////////// // Interface accessor methods /** * @return The underlying BayesNet */ public BayesNetIM getBayesNet() { return bayesNet; } /** * @param bn The new underlying BayesNet */ public synchronized void setBayesNet(BayesNetIM bn) { if (bn == null) bn = createBayesNet(); bayesNet = bn; tGraph = createTetradGraph(); firePropertyChange("bayesNet", null, null); } /** * @return The mode of the Workbench */ public int getMode() { return mode; } /** * @param newMode The new mode of the Workbench */ public synchronized void setMode(int newMode) { if ((newMode != SETUP_GATHER_MODE) && (newMode != HYPOTHESIZE_PREDICT_MODE)) return; int oldMode = mode; mode = newMode; firePropertyChange("mode", new Integer(oldMode), new Integer(mode)); } /** * @return The tool of the Workbench */ public int getTool() { return tool; } /** * @param newTool The new tool of the Workbench */ public synchronized void setTool(int newTool) { switch(newTool) { case MOVE: case LOCK: case RANDOMIZER: case ARROW: case LATENT: break; default: return; } int oldTool = tool; tool = newTool; firePropertyChange("tool", new Integer(oldTool), new Integer(newTool)); } // TetradGraph methods /** * @return The user-constructed TetradGraph */ public TetradGraph getTetradGraph() { return tGraph; } /** * @param tg The new "user-constructed" TetradGraph */ public synchronized void setTetradGraph(TetradGraph tg) { if (tg == null) tg = createTetradGraph(); tGraph = tg; firePropertyChange("tetradGraph", null, null); } /** * Adds an edge to the TetradGraph from the WBVariable with name * from, to the WBVariable with name to. * @param from The name of the "from" WBVariable * @param to The name of the "to" WBVariable */ public void addEdge(String from, String to) { try { tGraph.addDirectedEdge(tGraph.getNodeFor(from), tGraph.getNodeFor(to)); } catch (PropertyVetoException pve) { System.out.println("Couldn't add edge from "+from+" to "+to); System.out.println(pve.toString()); return; } } /** * Removes the edge in the TetradGraph from the WBVariable with name * from, to the WBVariable with name to. * @param from The name of the "from" WBVariable * @param to The name of the "to" WBVariable */ public void removeEdge(String from, String to) { try { tGraph.removeEdges(tGraph.getNodeFor(from), tGraph.getNodeFor(to)); } catch (PropertyVetoException pve) { System.out.println("Couldn't remove edge from "+from+" to "+to); System.out.println(pve.toString()); return; } } /** * Adds a latent node with the given name to the TetradGraph * @param name The name of the latent variable */ public void addLatent(String name) { Variable lat = new Variable(name); lat.setLatent(); try { tGraph.addNode(lat); } catch (PropertyVetoException pve) { System.out.println("Couldn't add latent: "+pve.toString()); return; } } /** * Removes the latent node with the given name * @param name The name of the latent variable */ public void removeLatent(String name) { // removeNode() removes edges also try { tGraph.removeNode(tGraph.getNodeFor(name)); } catch (PropertyVetoException pve) { System.out.println("Problem removing latent: "+pve.toString()); return; } } // PropertyChangeListener methods /** * @param l The PropertChangeListener to add for this WorkbenchModel */ public void addPropertyChangeListener(PropertyChangeListener l) { listenerList.add(PropertyChangeListener.class, l); } /** * @param l The PropertChangeListener to remove for this WorkbenchModel */ public void removePropertyChangeListener(PropertyChangeListener l) { listenerList.remove(PropertyChangeListener.class, l); } /** * Send out a PropertyChangeEvent with the given parameters to all registered * PropertyChangeListeners * @param propName The name of the changed property * @param oldVal The old value of the changed property * @param newVal The new value of the changed property */ protected void firePropertyChange(String propName, Object oldVal, Object newVal) { PropertyChangeEvent pce = new PropertyChangeEvent(this, propName, oldVal, newVal); Object[] listeners = listenerList.getListenerList(); for (int i=listeners.length-2; i >=0; i -= 2) { if (listeners[i] == PropertyChangeListener.class) ((PropertyChangeListener)listeners[i+1]).propertyChange(pce); } } // Set-up methods /** * @return A minimal BayesNet */ private BayesNetIM createBayesNet() { DirectedAcyclicGraph dag = new DirectedAcyclicGraph(); try { dag.addNode(new Variable("default")); } catch (PropertyVetoException pve) { System.out.println("Problem adding node: "+pve.toString()); return null; } BayesNetPM bnpm = new BayesNetPM(dag); return new BayesNetIM(bnpm); } /** * Creates a TetradGraph with no edges using the underlying BayesNet's variables. * @return A no-edge TetradGraph with the BayesNet's variables */ private TetradGraph createTetradGraph() { TetradGraph newGraph = new TetradGraph(); Iterator it = bayesNet.nodeIterator(); while (it.hasNext()) { Node node = (Node)it.next(); try { newGraph.addNode(node); } catch (PropertyVetoException pve) { System.out.println("Can't add node: "+node.toString()); return null; } } return newGraph; } /** * Resets the TetradGraph to a no-edge Graph. Note: this method does _not_ * remove any nodes (including latents); it just removes edges. */ public void resetTetradGraph() { try { tGraph.removeAllEdges(); } catch (PropertyVetoException pve) { System.out.println("Can't remove all edges: "+pve.toString()); return; } } // Misc. Object methods /** * @return A String representation of the WorkbenchModel */ public String toString() { String vals = "mode="+mode; vals += ";tool="+tool; return getClass().getName()+"["+vals+"]"; } }