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: *
* The following PropertyChangeEvent
s 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 inSETUP_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+"]";
}
}