Coverage Report - weka.classifiers.bayes.net.EditableBayesNet
 
Classes in this File Line Coverage Branch Coverage Complexity
EditableBayesNet
0%
0/777
0%
0/414
2.936
EditableBayesNet$AddArcAction
0%
0/40
0%
0/6
2.936
EditableBayesNet$AddNodeAction
0%
0/16
N/A
2.936
EditableBayesNet$AddValueAction
0%
0/13
N/A
2.936
EditableBayesNet$DelValueAction
0%
0/37
0%
0/8
2.936
EditableBayesNet$DeleteArcAction
0%
0/27
0%
0/4
2.936
EditableBayesNet$DeleteNodeAction
0%
0/59
0%
0/18
2.936
EditableBayesNet$DeleteSelectionAction
0%
0/80
0%
0/36
2.936
EditableBayesNet$LayoutGraphAction
0%
0/17
0%
0/6
2.936
EditableBayesNet$PasteAction
0%
0/17
0%
0/2
2.936
EditableBayesNet$RenameAction
0%
0/9
N/A
2.936
EditableBayesNet$RenameValueAction
0%
0/9
N/A
2.936
EditableBayesNet$SetDistributionAction
0%
0/22
N/A
2.936
EditableBayesNet$SetGroupPositionAction
0%
0/18
0%
0/6
2.936
EditableBayesNet$SetPositionAction
0%
0/14
N/A
2.936
EditableBayesNet$UndoAction
0%
0/15
0%
0/4
2.936
EditableBayesNet$alignAction
0%
0/17
0%
0/4
2.936
EditableBayesNet$alignBottomAction
0%
0/10
N/A
2.936
EditableBayesNet$alignLeftAction
0%
0/10
N/A
2.936
EditableBayesNet$alignRightAction
0%
0/10
N/A
2.936
EditableBayesNet$alignTopAction
0%
0/10
N/A
2.936
EditableBayesNet$centerHorizontalAction
0%
0/10
N/A
2.936
EditableBayesNet$centerVerticalAction
0%
0/10
N/A
2.936
EditableBayesNet$spaceHorizontalAction
0%
0/10
N/A
2.936
EditableBayesNet$spaceVerticalAction
0%
0/10
N/A
2.936
 
 1  
 /*
 2  
  *   This program is free software: you can redistribute it and/or modify
 3  
  *   it under the terms of the GNU General Public License as published by
 4  
  *   the Free Software Foundation, either version 3 of the License, or
 5  
  *   (at your option) any later version.
 6  
  *
 7  
  *   This program is distributed in the hope that it will be useful,
 8  
  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 9  
  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 10  
  *   GNU General Public License for more details.
 11  
  *
 12  
  *   You should have received a copy of the GNU General Public License
 13  
  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 14  
  */
 15  
 
 16  
 /*
 17  
  * EditableBayesNet.java
 18  
  * Copyright (C) 2012 University of Waikato, Hamilton, New Zealand
 19  
  * 
 20  
  */
 21  
 
 22  
 package weka.classifiers.bayes.net;
 23  
 
 24  
 import java.io.Serializable;
 25  
 import java.io.StringReader;
 26  
 import java.util.StringTokenizer;
 27  
 
 28  
 import javax.xml.parsers.DocumentBuilderFactory;
 29  
 
 30  
 import org.w3c.dom.CharacterData;
 31  
 import org.w3c.dom.Document;
 32  
 import org.w3c.dom.Element;
 33  
 import org.w3c.dom.Node;
 34  
 import org.w3c.dom.NodeList;
 35  
 
 36  
 import weka.classifiers.bayes.BayesNet;
 37  
 import weka.classifiers.bayes.net.estimate.DiscreteEstimatorBayes;
 38  
 import weka.core.Attribute;
 39  
 import weka.core.FastVector;
 40  
 import weka.core.Instances;
 41  
 import weka.core.RevisionUtils;
 42  
 import weka.core.SerializedObject;
 43  
 import weka.estimators.Estimator;
 44  
 import weka.filters.Filter;
 45  
 import weka.filters.unsupervised.attribute.Reorder;
 46  
 
 47  
 
 48  
 /**
 49  
  <!-- globalinfo-start -->
 50  
  * Bayes Network learning using various search algorithms and quality measures.<br/>
 51  
  * Base class for a Bayes Network classifier. Provides datastructures (network structure, conditional probability distributions, etc.) and facilities common to Bayes Network learning algorithms like K2 and B.<br/>
 52  
  * <br/>
 53  
  * For more information see:<br/>
 54  
  * <br/>
 55  
  * http://www.cs.waikato.ac.nz/~remco/weka.pdf
 56  
  * <p/>
 57  
  <!-- globalinfo-end -->
 58  
  *
 59  
  <!-- options-start -->
 60  
  * Valid options are: <p/>
 61  
  * 
 62  
  * <pre> -D
 63  
  *  Do not use ADTree data structure
 64  
  * </pre>
 65  
  * 
 66  
  * <pre> -B &lt;BIF file&gt;
 67  
  *  BIF file to compare with
 68  
  * </pre>
 69  
  * 
 70  
  * <pre> -Q weka.classifiers.bayes.net.search.SearchAlgorithm
 71  
  *  Search algorithm
 72  
  * </pre>
 73  
  * 
 74  
  * <pre> -E weka.classifiers.bayes.net.estimate.SimpleEstimator
 75  
  *  Estimator algorithm
 76  
  * </pre>
 77  
  * 
 78  
  <!-- options-end -->
 79  
  *
 80  
  * @author Remco Bouckaert (rrb@xm.co.nz)
 81  
  * @version $Revision: 8034 $
 82  
  */
 83  
 
 84  0
 public class EditableBayesNet extends BayesNet {
 85  
         /** for serialization */
 86  
         static final long serialVersionUID = 746037443258735954L;
 87  
 
 88  
         /** location of nodes, used for graph drawing * */
 89  
         protected FastVector m_nPositionX;
 90  
 
 91  
         protected FastVector m_nPositionY;
 92  
 
 93  
         /** marginal distributions * */
 94  
         protected FastVector m_fMarginP;
 95  
 
 96  
         /** evidence values, used for evidence propagation * */
 97  
         protected FastVector m_nEvidence;
 98  
 
 99  
         /** standard constructor * */
 100  
         public EditableBayesNet() {
 101  0
                 super();
 102  0
                 m_nEvidence = new FastVector(0);
 103  0
                 m_fMarginP = new FastVector(0);
 104  0
                 m_nPositionX = new FastVector();
 105  0
                 m_nPositionY = new FastVector();
 106  0
                 clearUndoStack();
 107  0
         } // c'tor
 108  
 
 109  
         /** constructor, creates empty network with nodes based on the attributes in a data set */
 110  0
         public EditableBayesNet(Instances instances) {
 111  
                 try {
 112  0
                         if (instances.classIndex() < 0) {
 113  0
                                 instances.setClassIndex(instances.numAttributes() - 1);
 114  
                         }
 115  0
                         m_Instances = normalizeDataSet(instances);
 116  0
                 } catch (Exception e) {
 117  0
                         e.printStackTrace();
 118  0
                 }
 119  
 
 120  0
                 int nNodes = getNrOfNodes();
 121  0
                 m_ParentSets = new ParentSet[nNodes];
 122  0
                 for (int i = 0; i < nNodes; i++) {
 123  0
                         m_ParentSets[i] = new ParentSet();
 124  
                 }
 125  0
                 m_Distributions = new Estimator[nNodes][];
 126  0
                 for (int iNode = 0; iNode < nNodes; iNode++) {
 127  0
                         m_Distributions[iNode] = new Estimator[1];
 128  0
                         m_Distributions[iNode][0] = new DiscreteEstimatorBayes(getCardinality(iNode), 0.5);
 129  
                 }
 130  
 
 131  0
                 m_nEvidence = new FastVector(nNodes);
 132  0
                 for (int i = 0; i < nNodes; i++) {
 133  0
                         m_nEvidence.addElement(-1);
 134  
                 }
 135  0
                 m_fMarginP = new FastVector(nNodes);
 136  0
                 for (int i = 0; i < nNodes; i++) {
 137  0
                         double[] P = new double[getCardinality(i)];
 138  0
                         m_fMarginP.addElement(P);
 139  
                 }
 140  
 
 141  0
                 m_nPositionX = new FastVector(nNodes);
 142  0
                 m_nPositionY = new FastVector(nNodes);
 143  0
                 for (int iNode = 0; iNode < nNodes; iNode++) {
 144  0
                         m_nPositionX.addElement(iNode%10 * 50);
 145  0
                         m_nPositionY.addElement(((int)(iNode/10)) * 50);
 146  
                 }
 147  
 
 148  0
         } // c'tor
 149  
 
 150  
         /** constructor, copies Bayesian network structure from a Bayesian network
 151  
          * encapsulated in a BIFReader
 152  
          */
 153  0
         public EditableBayesNet(BIFReader other) {
 154  0
                 m_Instances = other.m_Instances;
 155  0
                 m_ParentSets = other.getParentSets();
 156  0
                 m_Distributions = other.getDistributions();
 157  
 
 158  0
                 int nNodes = getNrOfNodes();
 159  0
                 m_nPositionX = new FastVector(nNodes);
 160  0
                 m_nPositionY = new FastVector(nNodes);
 161  0
                 for (int i = 0; i < nNodes; i++) {
 162  0
                         m_nPositionX.addElement(other.m_nPositionX[i]);
 163  0
                         m_nPositionY.addElement(other.m_nPositionY[i]);
 164  
                 }
 165  0
                 m_nEvidence = new FastVector(nNodes);
 166  0
                 for (int i = 0; i < nNodes; i++) {
 167  0
                         m_nEvidence.addElement(-1);
 168  
                 }
 169  0
                 m_fMarginP = new FastVector(nNodes);
 170  0
                 for (int i = 0; i < nNodes; i++) {
 171  0
                         double[] P = new double[getCardinality(i)];
 172  0
                         m_fMarginP.addElement(P);
 173  
                 }
 174  0
                 clearUndoStack();
 175  0
         } // c'tor
 176  
 
 177  
         /**
 178  
          * constructor that potentially initializes instances as well
 179  
          *
 180  
          * @param bSetInstances
 181  
          *            flag indicating whether to initialize instances or not
 182  
          */
 183  
         public EditableBayesNet(boolean bSetInstances) {
 184  0
                 super();
 185  0
                 m_nEvidence = new FastVector(0);
 186  0
                 m_fMarginP = new FastVector(0);
 187  0
                 m_nPositionX = new FastVector();
 188  0
                 m_nPositionY = new FastVector();
 189  0
                 clearUndoStack();
 190  0
                 if (bSetInstances) {
 191  0
                         m_Instances = new Instances("New Network", new FastVector(0), 0);
 192  
                 }
 193  0
         } // c'tor
 194  
 
 195  
 
 196  
         /** Assuming a network structure is defined and we want to learn from data,
 197  
          * the data set must be put if correct order first and possibly discretized/missing
 198  
          * values filled in before proceeding to CPT learning.
 199  
          * @param instances data set to learn from
 200  
          * @exception Exception when data sets are not compatible, e.g., a variable is missing
 201  
          * or a variable has different nr of values.
 202  
          */
 203  
         public void setData(Instances instances) throws Exception {
 204  
                 // sync order of variables
 205  0
                 int [] order = new int [getNrOfNodes()];
 206  0
                 for (int iNode = 0; iNode < getNrOfNodes(); iNode++) {
 207  0
                         String sName = getNodeName(iNode);
 208  0
                         int nNode = 0;
 209  0
                         while (nNode < getNrOfNodes() && !sName.equals(instances.attribute(nNode).name())) {
 210  0
                                 nNode++;
 211  
                         }
 212  0
                         if (nNode >= getNrOfNodes()) {
 213  0
                                 throw new Exception("Cannot find node named [[[" + sName + "]]] in the data");
 214  
                         }
 215  0
                         order[iNode] = nNode;
 216  
                 }
 217  0
                 Reorder reorderFilter = new Reorder();
 218  0
                 reorderFilter.setAttributeIndicesArray(order);
 219  0
                 reorderFilter.setInputFormat(instances);
 220  0
                 instances = Filter.useFilter(instances, reorderFilter);
 221  
                 // filter using discretization/missing values filter
 222  0
                 Instances newInstances = new Instances(m_Instances, 0);
 223  0
                 if (m_DiscretizeFilter == null && m_MissingValuesFilter == null) {
 224  0
                         newInstances = normalizeDataSet(instances);
 225  
                 } else {
 226  0
                         for (int iInstance = 0; iInstance < instances.numInstances(); iInstance++) {
 227  0
                                 newInstances.add(normalizeInstance(instances.instance(iInstance)));
 228  
                         }
 229  
                 }
 230  
                 //sanity check
 231  0
                 for (int iNode = 0; iNode < getNrOfNodes(); iNode++) {
 232  0
                         if (newInstances.attribute(iNode).numValues() != getCardinality(iNode)) {
 233  0
                                 throw new Exception("Number of values of node [[[" + getNodeName(iNode) + "]]] differs in (discretized) dataset." );
 234  
                         }
 235  
                 }
 236  
                 // if we got this far, all is ok with the data set and
 237  
                 // we can replace data set of Bayes net
 238  0
                 m_Instances = newInstances;
 239  0
         } // setData
 240  
 
 241  
         /** returns index of node with given name, or -1 if no such node exists
 242  
          * @param sNodeName name of the node to get index for
 243  
          */
 244  
         public int getNode2(String sNodeName) {
 245  0
                 int iNode = 0;
 246  0
                 while (iNode < m_Instances.numAttributes()) {
 247  0
                         if (m_Instances.attribute(iNode).name().equals(sNodeName)) {
 248  0
                                 return iNode;
 249  
                         }
 250  0
                         iNode++;
 251  
                 }
 252  0
                 return -1;
 253  
         } // getNode2
 254  
 
 255  
         /** returns index of node with given name. Throws exception if no such node exists
 256  
          * @param sNodeName name of the node to get index for
 257  
          */
 258  
         public int getNode(String sNodeName) throws Exception {
 259  0
                 int iNode = getNode2(sNodeName);
 260  0
                 if (iNode < 0) {
 261  0
                         throw new Exception("Could not find node [[" + sNodeName + "]]");
 262  
                 }
 263  0
                 return iNode;
 264  
         } // getNode
 265  
 
 266  
         /**
 267  
          * Add new node to the network, initializing instances, parentsets,
 268  
          * distributions. Used for manual manipulation of the Bayesian network.
 269  
          *
 270  
          * @param sName
 271  
          *            name of the node. If the name already exists, an x is appended
 272  
          *            to the name
 273  
          * @param nCardinality
 274  
          *            number of values for this node
 275  
          * @throws Exception
 276  
          */
 277  
         public void addNode(String sName, int nCardinality) throws Exception {
 278  0
                 addNode(sName, nCardinality, 100 + getNrOfNodes() * 10, 100 + getNrOfNodes() * 10);
 279  0
         } // addNode
 280  
 
 281  
         /** Add node to network at a given position, initializing instances, parentsets,
 282  
          * distributions. Used for manual manipulation of the Bayesian network.
 283  
          *
 284  
          * @param sName
 285  
          *            name of the node. If the name already exists, an x is appended
 286  
          *            to the name
 287  
          * @param nCardinality
 288  
          *            number of values for this node
 289  
          * @param nPosX x-coordiate of the position to place this node
 290  
          * @param nPosY y-coordiate of the position to place this node
 291  
          * @throws Exception
 292  
          */
 293  
         public void addNode(String sName, int nCardinality, int nPosX, int nPosY) throws Exception {
 294  0
                 if (getNode2(sName) >= 0) {
 295  0
                         addNode(sName + "x", nCardinality);
 296  0
                         return ;
 297  
                 }
 298  
                 // update instances
 299  0
                 FastVector values = new FastVector(nCardinality);
 300  0
                 for (int iValue = 0; iValue < nCardinality; iValue++) {
 301  0
                         values.addElement("Value" + (iValue + 1));
 302  
                 }
 303  0
                 Attribute att = new Attribute(sName, values);
 304  0
                 m_Instances.insertAttributeAt(att, m_Instances.numAttributes());
 305  0
                 int nAtts = m_Instances.numAttributes();
 306  
                 // update parentsets
 307  0
                 ParentSet[] parentSets = new ParentSet[nAtts];
 308  0
                 for (int iParentSet = 0; iParentSet < nAtts - 1; iParentSet++) {
 309  0
                         parentSets[iParentSet] = m_ParentSets[iParentSet];
 310  
                 }
 311  0
                 parentSets[nAtts - 1] = new ParentSet();
 312  0
                 m_ParentSets = parentSets;
 313  
                 // update distributions
 314  0
                 Estimator[][] distributions = new Estimator[nAtts][];
 315  0
                 for (int iNode = 0; iNode < nAtts - 1; iNode++) {
 316  0
                         distributions[iNode] = m_Distributions[iNode];
 317  
                 }
 318  0
                 distributions[nAtts - 1] = new Estimator[1];
 319  0
                 distributions[nAtts - 1][0] = new DiscreteEstimatorBayes(nCardinality, 0.5);
 320  0
                 m_Distributions = distributions;
 321  
                 // update positions
 322  0
                 m_nPositionX.addElement(nPosX);
 323  0
                 m_nPositionY.addElement(nPosY);
 324  
                 // update evidence & margins
 325  0
                 m_nEvidence.addElement(-1);
 326  0
                 double[] fMarginP = new double[nCardinality];
 327  0
                 for (int iValue = 0; iValue < nCardinality; iValue++) {
 328  0
                         fMarginP[iValue] = 1.0 / nCardinality;
 329  
                 }
 330  0
                 m_fMarginP.addElement(fMarginP);
 331  
                 // update undo stack
 332  0
                 if (m_bNeedsUndoAction) {
 333  0
                         addUndoAction(new AddNodeAction(sName, nCardinality, nPosX, nPosY));
 334  
                 }
 335  0
         } // addNode
 336  
 
 337  
         /**
 338  
          * Delete node from the network, updating instances, parentsets,
 339  
          * distributions Conditional distributions are condensed by taking the
 340  
          * values for the target node to be its first value. Used for manual
 341  
          * manipulation of the Bayesian network.
 342  
          *
 343  
          * @param sName
 344  
          *            name of the node. If the name does not exists an exception is
 345  
          *            thrown
 346  
          * @throws Exception
 347  
          */
 348  
         public void deleteNode(String sName) throws Exception {
 349  0
                 int nTargetNode = getNode(sName);
 350  0
                 deleteNode(nTargetNode);
 351  0
         } // deleteNode
 352  
 
 353  
         /**
 354  
          * Delete node from the network, updating instances, parentsets,
 355  
          * distributions Conditional distributions are condensed by taking the
 356  
          * values for the target node to be its first value. Used for manual
 357  
          * manipulation of the Bayesian network.
 358  
          *
 359  
          * @param nTargetNode
 360  
          *            index of the node to delete.
 361  
          * @throws Exception
 362  
          */
 363  
         public void deleteNode(int nTargetNode) throws Exception {
 364  
                 // update undo stack
 365  0
                 if (m_bNeedsUndoAction) {
 366  0
                         addUndoAction(new DeleteNodeAction(nTargetNode));
 367  
                 }
 368  0
                 int nAtts = m_Instances.numAttributes() - 1;
 369  0
                 int nTargetCard = m_Instances.attribute(nTargetNode).numValues();
 370  
                 // update distributions
 371  0
                 Estimator[][] distributions = new Estimator[nAtts][];
 372  0
                 for (int iNode = 0; iNode < nAtts; iNode++) {
 373  0
                         int iNode2 = iNode;
 374  0
                         if (iNode >= nTargetNode) {
 375  0
                                 iNode2++;
 376  
                         }
 377  0
                         Estimator[] distribution = m_Distributions[iNode2];
 378  0
                         if (m_ParentSets[iNode2].contains(nTargetNode)) {
 379  
                                 // condense distribution, use values for targetnode = 0
 380  0
                                 int nParentCard = m_ParentSets[iNode2].getCardinalityOfParents();
 381  0
                                 nParentCard = nParentCard / nTargetCard;
 382  0
                                 Estimator[] distribution2 = new Estimator[nParentCard];
 383  0
                                 for (int iParent = 0; iParent < nParentCard; iParent++) {
 384  0
                                         distribution2[iParent] = distribution[iParent];
 385  
                                 }
 386  0
                                 distribution = distribution2;
 387  
                         }
 388  0
                         distributions[iNode] = distribution;
 389  
                 }
 390  0
                 m_Distributions = distributions;
 391  
                 // update parentsets
 392  0
                 ParentSet[] parentSets = new ParentSet[nAtts];
 393  0
                 for (int iParentSet = 0; iParentSet < nAtts; iParentSet++) {
 394  0
                         int iParentSet2 = iParentSet;
 395  0
                         if (iParentSet >= nTargetNode) {
 396  0
                                 iParentSet2++;
 397  
                         }
 398  0
                         ParentSet parentset = m_ParentSets[iParentSet2];
 399  0
                         parentset.deleteParent(nTargetNode, m_Instances);
 400  0
                         for (int iParent = 0; iParent < parentset.getNrOfParents(); iParent++) {
 401  0
                                 int nParent = parentset.getParent(iParent);
 402  0
                                 if (nParent > nTargetNode) {
 403  0
                                         parentset.SetParent(iParent, nParent - 1);
 404  
                                 }
 405  
                         }
 406  0
                         parentSets[iParentSet] = parentset;
 407  
                 }
 408  0
                 m_ParentSets = parentSets;
 409  
                 // update instances
 410  0
                 m_Instances.setClassIndex(-1);
 411  0
                 m_Instances.deleteAttributeAt(nTargetNode);
 412  0
                 m_Instances.setClassIndex(nAtts - 1);
 413  
 
 414  
                 // update positions
 415  0
                 m_nPositionX.removeElementAt(nTargetNode);
 416  0
                 m_nPositionY.removeElementAt(nTargetNode);
 417  
                 // update evidence & margins
 418  0
                 m_nEvidence.removeElementAt(nTargetNode);
 419  0
                 m_fMarginP.removeElementAt(nTargetNode);
 420  0
         } // deleteNode
 421  
 
 422  
         /**
 423  
          * Delete nodes with indexes in selection from the network, updating instances, parentsets,
 424  
          * distributions Conditional distributions are condensed by taking the
 425  
          * values for the target node to be its first value. Used for manual
 426  
          * manipulation of the Bayesian network.
 427  
          *
 428  
          * @param nodes
 429  
          *            array of indexes of nodes to delete.
 430  
          * @throws Exception
 431  
          */
 432  
         public void deleteSelection(FastVector nodes) {
 433  
                 // sort before proceeding
 434  0
                 for (int i = 0; i < nodes.size(); i++) {
 435  0
                         for (int j = i + 1; j < nodes.size(); j++) {
 436  0
                                 if ((Integer) nodes.elementAt(i) > (Integer) nodes.elementAt(j)) {
 437  0
                                         int h = (Integer) nodes.elementAt(i);
 438  0
                                         nodes.setElementAt(nodes.elementAt(j), i);
 439  0
                                         nodes.setElementAt(h, j);
 440  
                                 }
 441  
                         }
 442  
                 }
 443  
                 // update undo stack
 444  0
                 if (m_bNeedsUndoAction) {
 445  0
                         addUndoAction(new DeleteSelectionAction(nodes));
 446  
                 }
 447  0
                 boolean bNeedsUndoAction = m_bNeedsUndoAction;
 448  0
                 m_bNeedsUndoAction = false;
 449  
                 try {
 450  0
                         for (int iNode = nodes.size() - 1; iNode >= 0; iNode--) {
 451  0
                                 deleteNode((Integer) nodes.elementAt(iNode));
 452  
                         }
 453  0
                 } catch (Exception e) {
 454  0
                         e.printStackTrace();
 455  0
                 }
 456  0
                 m_bNeedsUndoAction = bNeedsUndoAction;
 457  0
         } // deleteSelection
 458  
 
 459  
         /** XML helper function for selecting elements under a node with a given name
 460  
          * @param item XMLNode to select items from
 461  
          * @param sElement name of the element to return
 462  
          */
 463  
         FastVector selectElements(Node item, String sElement) throws Exception {
 464  0
                 NodeList children = item.getChildNodes();
 465  0
                 FastVector nodelist = new FastVector();
 466  0
                 for (int iNode = 0; iNode < children.getLength(); iNode++) {
 467  0
                         Node node = children.item(iNode);
 468  0
                         if ((node.getNodeType() == Node.ELEMENT_NODE) && node.getNodeName().equals(sElement)) {
 469  0
                                 nodelist.addElement(node);
 470  
                         }
 471  
                 }
 472  0
                 return nodelist;
 473  
         } // selectElements
 474  
 
 475  
         /**
 476  
          * XML helper function. Returns all TEXT children of the given node in one string. Between the
 477  
          * node values new lines are inserted.
 478  
          *
 479  
          * @param node
 480  
          *            the node to return the content for
 481  
          * @return the content of the node
 482  
          */
 483  
         public String getContent(Element node) {
 484  
                 NodeList list;
 485  
                 Node item;
 486  
                 int i;
 487  
                 String result;
 488  
 
 489  0
                 result = "";
 490  0
                 list = node.getChildNodes();
 491  
 
 492  0
                 for (i = 0; i < list.getLength(); i++) {
 493  0
                         item = list.item(i);
 494  0
                         if (item.getNodeType() == Node.TEXT_NODE)
 495  0
                                 result += "\n" + item.getNodeValue();
 496  
                 }
 497  
 
 498  0
                 return result;
 499  
         }
 500  
 
 501  
         /** XML helper function that returns DEFINITION element from a XMLBIF document
 502  
          * for a node with a given name.
 503  
          * @param doc XMLBIF document
 504  
          * @param sName name of the node to get the definition for
 505  
          */
 506  
         Element getDefinition(Document doc, String sName) throws Exception {
 507  0
                 NodeList nodelist = doc.getElementsByTagName("DEFINITION");
 508  0
                 for (int iNode = 0; iNode < nodelist.getLength(); iNode++) {
 509  0
                         Node node = nodelist.item(iNode);
 510  0
                         FastVector list = selectElements(node, "FOR");
 511  0
                         if (list.size() > 0) {
 512  0
                                 Node forNode = (Node) list.elementAt(0);
 513  0
                                 if (getContent((Element) forNode).trim().equals(sName)) {
 514  0
                                         return (Element) node;
 515  
                                 }
 516  
                         }
 517  
                 }
 518  0
                 throw new Exception("Could not find definition for ((" + sName + "))");
 519  
         } // getDefinition
 520  
 
 521  
 
 522  
         /** Paste modes. This allows for verifying that a past action does not cause
 523  
          * any problems before actually performing the paste operation.
 524  
          */
 525  
         final static int TEST = 0;
 526  
         final static int EXECUTE = 1;
 527  
 
 528  
         /** Apply paste operation with XMLBIF fragment. This adds nodes in the XMLBIF fragment
 529  
          * to the network, together with its parents. First, paste in test mode to verify
 530  
          * no problems occur, then execute paste operation. If a problem occurs (e.g. parent
 531  
          * does not exist) then a exception is thrown.
 532  
          * @param sXML XMLBIF fragment to paste into the network
 533  
          */
 534  
         public void paste(String sXML) throws Exception {
 535  
                 try {
 536  0
                         paste(sXML, TEST);
 537  0
                 } catch (Exception e) {
 538  0
                         throw e;
 539  0
                 }
 540  0
                 paste(sXML, EXECUTE);
 541  0
         } // paste
 542  
 
 543  
         /** Apply paste operation with XMLBIF fragment. Depending on the paste mode, the
 544  
          * nodes are actually added to the network or it is just tested that the nodes can
 545  
          * be added to the network.
 546  
          * @param sXML XMLBIF fragment to paste into the network
 547  
          * @param mode paste mode TEST or EXECUTE
 548  
          */
 549  
         void paste(String sXML, int mode) throws Exception {
 550  0
                 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
 551  0
                 factory.setValidating(true);
 552  0
                 Document doc = factory.newDocumentBuilder().parse(new org.xml.sax.InputSource(new StringReader(sXML)));
 553  0
                 doc.normalize();
 554  
 
 555  
                 // create nodes first
 556  0
                 NodeList nodelist = doc.getElementsByTagName("VARIABLE");
 557  0
                 FastVector sBaseNames = new FastVector();
 558  0
                 Instances instances = new Instances(m_Instances, 0);
 559  0
                 int nBase = instances.numAttributes();
 560  0
                 for (int iNode = 0; iNode < nodelist.getLength(); iNode++) {
 561  
                         // Get element
 562  
                         FastVector valueslist;
 563  
                         // Get the name of the node
 564  0
                         valueslist = selectElements(nodelist.item(iNode), "OUTCOME");
 565  
 
 566  0
                         int nValues = valueslist.size();
 567  
                         // generate value strings
 568  0
                         FastVector nomStrings = new FastVector(nValues + 1);
 569  0
                         for (int iValue = 0; iValue < nValues; iValue++) {
 570  0
                                 Node node = ((Node) valueslist.elementAt(iValue)).getFirstChild();
 571  0
                                 String sValue = ((CharacterData) (node)).getData();
 572  0
                                 if (sValue == null) {
 573  0
                                         sValue = "Value" + (iValue + 1);
 574  
                                 }
 575  0
                                 nomStrings.addElement(sValue);
 576  
                         }
 577  
                         FastVector nodelist2;
 578  
                         // Get the name of the network
 579  0
                         nodelist2 = selectElements(nodelist.item(iNode), "NAME");
 580  0
                         if (nodelist2.size() == 0) {
 581  0
                                 throw new Exception("No name specified for variable");
 582  
                         }
 583  0
                         String sBaseName = ((CharacterData) (((Node) nodelist2.elementAt(0)).getFirstChild())).getData();
 584  0
                         sBaseNames.addElement(sBaseName);
 585  0
                         String sNodeName = sBaseName;
 586  0
                         if (getNode2(sNodeName) >= 0) {
 587  0
                                 sNodeName = "Copy of " + sBaseName;
 588  
                         }
 589  0
                         int iAttempt = 2;
 590  0
                         while (getNode2(sNodeName) >= 0) {
 591  0
                                 sNodeName = "Copy (" + iAttempt + ") of " + sBaseName;
 592  0
                                 iAttempt++;
 593  
                         }
 594  
 
 595  0
                         Attribute att = new Attribute(sNodeName, nomStrings);
 596  0
                         instances.insertAttributeAt(att, instances.numAttributes());
 597  
 
 598  0
                         valueslist = selectElements(nodelist.item(iNode), "PROPERTY");
 599  0
                         nValues = valueslist.size();
 600  
                         // generate value strings
 601  0
                         int nPosX = iAttempt * 10;
 602  0
                         int nPosY = iAttempt * 10;
 603  0
                         for (int iValue = 0; iValue < nValues; iValue++) {
 604  
                                 // parsing for strings of the form "position = (73, 165)"
 605  0
                                 Node node = ((Node) valueslist.elementAt(iValue)).getFirstChild();
 606  0
                                 String sValue = ((CharacterData) (node)).getData();
 607  0
                                 if (sValue.startsWith("position")) {
 608  0
                                         int i0 = sValue.indexOf('(');
 609  0
                                         int i1 = sValue.indexOf(',');
 610  0
                                         int i2 = sValue.indexOf(')');
 611  0
                                         String sX = sValue.substring(i0 + 1, i1).trim();
 612  0
                                         String sY = sValue.substring(i1 + 1, i2).trim();
 613  
                                         try {
 614  0
                                                 nPosX = (Integer.parseInt(sX) + iAttempt * 10);
 615  0
                                                 nPosY = (Integer.parseInt(sY) + iAttempt * 10);
 616  0
                                         } catch (NumberFormatException e) {
 617  0
                                                 System.err.println("Wrong number format in position :(" + sX + "," + sY + ")");
 618  0
                                         }
 619  
                                 }
 620  
                         }
 621  0
                         if (mode == EXECUTE) {
 622  0
                                 m_nPositionX.addElement(nPosX);
 623  0
                                 m_nPositionY.addElement(nPosY);
 624  
                         }
 625  
 
 626  
                 }
 627  
 
 628  
                 FastVector nodelist2;
 629  0
                 Estimator[][] distributions = new Estimator[nBase + sBaseNames.size()][];
 630  0
                 ParentSet[] parentsets = new ParentSet[nBase + sBaseNames.size()];
 631  0
                 for (int iNode = 0; iNode < nBase; iNode++) {
 632  0
                         distributions[iNode] = m_Distributions[iNode];
 633  0
                         parentsets[iNode] = m_ParentSets[iNode];
 634  
                 }
 635  0
                 if (mode == EXECUTE) {
 636  0
                         m_Instances = instances;
 637  
                 }
 638  
                 // create arrows & create distributions
 639  0
                 for (int iNode = 0; iNode < sBaseNames.size(); iNode++) {
 640  
                         // find definition that goes with this node
 641  0
                         String sName = (String) sBaseNames.elementAt(iNode);
 642  0
                         Element definition = getDefinition(doc, sName);
 643  0
                         parentsets[nBase + iNode] = new ParentSet();
 644  
 
 645  
                         // get the parents for this node
 646  
                         // resolve structure
 647  0
                         nodelist2 = selectElements(definition, "GIVEN");
 648  0
                         for (int iParent = 0; iParent < nodelist2.size(); iParent++) {
 649  0
                                 Node parentName = ((Node) nodelist2.elementAt(iParent)).getFirstChild();
 650  0
                                 String sParentName = ((CharacterData) (parentName)).getData();
 651  0
                                 int nParent = -1;
 652  0
                                 for (int iBase = 0; iBase < sBaseNames.size(); iBase++) {
 653  0
                                         if (sParentName.equals((String) sBaseNames.elementAt(iBase))) {
 654  0
                                                 nParent = nBase + iBase;
 655  
                                         }
 656  
                                 }
 657  0
                                 if (nParent < 0) {
 658  0
                                         nParent = getNode(sParentName);
 659  
                                 }
 660  0
                                 parentsets[nBase + iNode].addParent(nParent, instances);
 661  
                         }
 662  
                         // resolve conditional probability table
 663  0
                         int nCardinality = parentsets[nBase + iNode].getCardinalityOfParents();
 664  0
                         int nValues = instances.attribute(nBase + iNode).numValues();
 665  0
                         distributions[nBase + iNode] = new Estimator[nCardinality];
 666  0
                         for (int i = 0; i < nCardinality; i++) {
 667  0
                                 distributions[nBase + iNode][i] = new DiscreteEstimatorBayes(nValues, 0.0f);
 668  
                         }
 669  
 
 670  0
                         String sTable = getContent((Element) selectElements(definition, "TABLE").elementAt(0));
 671  0
                         sTable = sTable.replaceAll("\\n", " ");
 672  0
                         StringTokenizer st = new StringTokenizer(sTable.toString());
 673  
 
 674  0
                         for (int i = 0; i < nCardinality; i++) {
 675  0
                                 DiscreteEstimatorBayes d = (DiscreteEstimatorBayes) distributions[nBase + iNode][i];
 676  0
                                 for (int iValue = 0; iValue < nValues; iValue++) {
 677  0
                                         String sWeight = st.nextToken();
 678  0
                                         d.addValue(iValue, new Double(sWeight).doubleValue());
 679  
                                 }
 680  
                         }
 681  0
                         if (mode == EXECUTE) {
 682  0
                                 m_nEvidence.insertElementAt(-1, nBase + iNode);
 683  0
                                 m_fMarginP.insertElementAt(new double[getCardinality(nBase + iNode)], nBase + iNode);
 684  
                         }
 685  
                 }
 686  0
                 if (mode == EXECUTE) {
 687  0
                         m_Distributions = distributions;
 688  0
                         m_ParentSets = parentsets;
 689  
                 }
 690  
                 // update undo stack
 691  0
                 if (mode == EXECUTE && m_bNeedsUndoAction) {
 692  0
                         addUndoAction(new PasteAction(sXML, nBase));
 693  
                 }
 694  0
         } // paste
 695  
 
 696  
         /**
 697  
          * Add arc between two nodes Distributions are updated by duplication for
 698  
          * every value of the parent node.
 699  
          *
 700  
          * @param sParent
 701  
          *            name of the parent node
 702  
          * @param sChild
 703  
          *            name of the child node
 704  
          * @throws Exception
 705  
          *             if parent or child cannot be found in network
 706  
          */
 707  
         public void addArc(String sParent, String sChild) throws Exception {
 708  0
                 int nParent = getNode(sParent);
 709  0
                 int nChild = getNode(sChild);
 710  0
                 addArc(nParent, nChild);
 711  0
         } // addArc
 712  
 
 713  
         /**
 714  
          * Add arc between two nodes Distributions are updated by duplication for
 715  
          * every value of the parent node.
 716  
          *
 717  
          * @param nParent
 718  
          *            index of the parent node
 719  
          * @param nChild
 720  
          *            index of the child node
 721  
          * @throws Exception
 722  
          */
 723  
         public void addArc(int nParent, int nChild) throws Exception {
 724  
                 // update undo stack
 725  0
                 if (m_bNeedsUndoAction) {
 726  0
                         addUndoAction(new AddArcAction(nParent, nChild));
 727  
                 }
 728  0
                 int nOldCard = m_ParentSets[nChild].getCardinalityOfParents();
 729  
                 // update parentsets
 730  0
                 m_ParentSets[nChild].addParent(nParent, m_Instances);
 731  
                 // update distributions
 732  0
                 int nNewCard = m_ParentSets[nChild].getCardinalityOfParents();
 733  0
                 Estimator[] ds = new Estimator[nNewCard];
 734  0
                 for (int iParent = 0; iParent < nNewCard; iParent++) {
 735  0
                         ds[iParent] = Estimator.clone(m_Distributions[nChild][iParent % nOldCard]);
 736  
                 }
 737  0
                 m_Distributions[nChild] = ds;
 738  0
         } // addArc
 739  
 
 740  
         /**
 741  
          * Add arc between parent node and each of the nodes in a given list.
 742  
          * Distributions are updated as above.
 743  
          *
 744  
          * @param sParent
 745  
          *            name of the parent node
 746  
          * @param nodes
 747  
          *            array of indexes of child nodes
 748  
          * @throws Exception
 749  
          */
 750  
         public void addArc(String sParent, FastVector nodes) throws Exception {
 751  0
                 int nParent = getNode(sParent);
 752  
                 // update undo stack
 753  0
                 if (m_bNeedsUndoAction) {
 754  0
                         addUndoAction(new AddArcAction(nParent, nodes));
 755  
                 }
 756  0
                 boolean bNeedsUndoAction = m_bNeedsUndoAction;
 757  0
                 m_bNeedsUndoAction = false;
 758  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 759  0
                         int nNode = (Integer) nodes.elementAt(iNode);
 760  0
                         addArc(nParent, nNode);
 761  
                 }
 762  0
                 m_bNeedsUndoAction = bNeedsUndoAction;
 763  0
         } // addArc
 764  
 
 765  
         /**
 766  
          * Delete arc between two nodes. Distributions are updated by condensing for
 767  
          * the parent node taking its first value.
 768  
          *
 769  
          * @param sParent
 770  
          *            name of the parent node
 771  
          * @param sChild
 772  
          *            name of the child node
 773  
          * @throws Exception
 774  
          *             if parent or child cannot be found in network
 775  
          */
 776  
         public void deleteArc(String sParent, String sChild) throws Exception {
 777  0
                 int nParent = getNode(sParent);
 778  0
                 int nChild = getNode(sChild);
 779  0
                 deleteArc(nParent, nChild);
 780  0
         } // deleteArc
 781  
 
 782  
         /**
 783  
          * Delete arc between two nodes. Distributions are updated by condensing for
 784  
          * the parent node taking its first value.
 785  
          *
 786  
          * @param nParent
 787  
          *            index of the parent node
 788  
          * @param nChild
 789  
          *            index of the child node
 790  
          * @throws Exception
 791  
          */
 792  
         public void deleteArc(int nParent, int nChild) throws Exception {
 793  
                 // update undo stack
 794  0
                 if (m_bNeedsUndoAction) {
 795  0
                         addUndoAction(new DeleteArcAction(nParent, nChild));
 796  
                 }
 797  
                 // update distributions
 798  
                 // condense distribution, use values for targetnode = 0
 799  0
                 int nParentCard = m_ParentSets[nChild].getCardinalityOfParents();
 800  0
                 int nTargetCard = m_Instances.attribute(nChild).numValues();
 801  0
                 nParentCard = nParentCard / nTargetCard;
 802  0
                 Estimator[] distribution2 = new Estimator[nParentCard];
 803  0
                 for (int iParent = 0; iParent < nParentCard; iParent++) {
 804  0
                         distribution2[iParent] = m_Distributions[nChild][iParent];
 805  
                 }
 806  0
                 m_Distributions[nChild] = distribution2;
 807  
                 // update parentsets
 808  0
                 m_ParentSets[nChild].deleteParent(nParent, m_Instances);
 809  0
         } // deleteArc
 810  
 
 811  
 
 812  
         /** specify distribution of a node
 813  
          * @param sName name of the node to specify distribution for
 814  
          * @param P matrix representing distribution with P[i][j] = P(node = j | parent configuration = i)
 815  
          * @throws Exception
 816  
          *             if parent or child cannot be found in network
 817  
          */
 818  
         public void setDistribution(String sName, double[][] P) throws Exception {
 819  0
                 int nTargetNode = getNode(sName);
 820  0
                 setDistribution(nTargetNode, P);
 821  0
         } // setDistribution
 822  
 
 823  
         /** specify distribution of a node
 824  
          * @param nTargetNode index of the node to specify distribution for
 825  
          * @param P matrix representing distribution with P[i][j] = P(node = j | parent configuration = i)
 826  
          * @throws Exception
 827  
          *             if parent or child cannot be found in network
 828  
          */
 829  
         public void setDistribution(int nTargetNode, double[][] P) throws Exception {
 830  
                 // update undo stack
 831  0
                 if (m_bNeedsUndoAction) {
 832  0
                         addUndoAction(new SetDistributionAction(nTargetNode, P));
 833  
                 }
 834  0
                 Estimator[] distributions = m_Distributions[nTargetNode];
 835  0
                 for (int iParent = 0; iParent < distributions.length; iParent++) {
 836  0
                         DiscreteEstimatorBayes distribution = new DiscreteEstimatorBayes(P[0].length, 0);
 837  0
                         for (int iValue = 0; iValue < distribution.getNumSymbols(); iValue++) {
 838  0
                                 distribution.addValue(iValue, P[iParent][iValue]);
 839  
                         }
 840  0
                         distributions[iParent] = distribution;
 841  
                 }
 842  
                 // m_Distributions[nTargetNode] = distributions;
 843  0
         } // setDistribution
 844  
 
 845  
         /** returns distribution of a node in matrix form with matrix representing distribution
 846  
          * with P[i][j] = P(node = j | parent configuration = i)
 847  
          * @param sName name of the node to get distribution from
 848  
          */
 849  
         public double[][] getDistribution(String sName) {
 850  0
                 int nTargetNode = getNode2(sName);
 851  0
                 return getDistribution(nTargetNode);
 852  
         } // getDistribution
 853  
 
 854  
         /** returns distribution of a node in matrix form with matrix representing distribution
 855  
          * with P[i][j] = P(node = j | parent configuration = i)
 856  
          * @param nTargetNode index of the node to get distribution from
 857  
          */
 858  
         public double[][] getDistribution(int nTargetNode) {
 859  0
                 int nParentCard = m_ParentSets[nTargetNode].getCardinalityOfParents();
 860  0
                 int nCard = m_Instances.attribute(nTargetNode).numValues();
 861  0
                 double[][] P = new double[nParentCard][nCard];
 862  0
                 for (int iParent = 0; iParent < nParentCard; iParent++) {
 863  0
                         for (int iValue = 0; iValue < nCard; iValue++) {
 864  0
                                 P[iParent][iValue] = m_Distributions[nTargetNode][iParent].getProbability(iValue);
 865  
                         }
 866  
                 }
 867  0
                 return P;
 868  
         } // getDistribution
 869  
 
 870  
         /** returns array of values of a node
 871  
          * @param sName name of the node to get values from
 872  
          */
 873  
         public String[] getValues(String sName) {
 874  0
                 int nTargetNode = getNode2(sName);
 875  0
                 return getValues(nTargetNode);
 876  
         } // getValues
 877  
 
 878  
         /** returns array of values of a node
 879  
          * @param nTargetNode index of the node to get values from
 880  
          */
 881  
         public String[] getValues(int nTargetNode) {
 882  0
                 String[] values = new String[getCardinality(nTargetNode)];
 883  0
                 for (int iValue = 0; iValue < values.length; iValue++) {
 884  0
                         values[iValue] = m_Instances.attribute(nTargetNode).value(iValue);
 885  
                 }
 886  0
                 return values;
 887  
         } // getValues
 888  
 
 889  
         /** returns value of a node
 890  
          * @param nTargetNode index of the node to get values from
 891  
          * @param iValue index of the value
 892  
          */
 893  
         public String getValueName(int nTargetNode, int iValue) {
 894  0
                 return m_Instances.attribute(nTargetNode).value(iValue);
 895  
         } // getNodeValue
 896  
 
 897  
         /** change the name of a node
 898  
          * @param nTargetNode index of the node to set name for
 899  
          * @param sName new name to assign
 900  
          */
 901  
         public void setNodeName(int nTargetNode, String sName) {
 902  
                 // update undo stack
 903  0
                 if (m_bNeedsUndoAction) {
 904  0
                         addUndoAction(new RenameAction(nTargetNode, getNodeName(nTargetNode), sName));
 905  
                 }
 906  0
                 Attribute att = m_Instances.attribute(nTargetNode);
 907  0
                 int nCardinality = att.numValues();
 908  0
                 FastVector values = new FastVector(nCardinality);
 909  0
                 for (int iValue = 0; iValue < nCardinality; iValue++) {
 910  0
                         values.addElement(att.value(iValue));
 911  
                 }
 912  0
                 replaceAtt(nTargetNode, sName, values);
 913  0
         } // setNodeName
 914  
 
 915  
         /** change the name of a value of a node
 916  
          * @param nTargetNode index of the node to set name for
 917  
          * @param sValue current name of the value
 918  
          * @param sNewValue new name of the value
 919  
          */
 920  
         public void renameNodeValue(int nTargetNode, String sValue, String sNewValue) {
 921  
                 // update undo stack
 922  0
                 if (m_bNeedsUndoAction) {
 923  0
                         addUndoAction(new RenameValueAction(nTargetNode, sValue, sNewValue));
 924  
                 }
 925  0
                 Attribute att = m_Instances.attribute(nTargetNode);
 926  0
                 int nCardinality = att.numValues();
 927  0
                 FastVector values = new FastVector(nCardinality);
 928  0
                 for (int iValue = 0; iValue < nCardinality; iValue++) {
 929  0
                         if (att.value(iValue).equals(sValue)) {
 930  0
                                 values.addElement(sNewValue);
 931  
                         } else {
 932  0
                                 values.addElement(att.value(iValue));
 933  
                         }
 934  
                 }
 935  0
                 replaceAtt(nTargetNode, att.name(), values);
 936  0
         } // renameNodeValue
 937  
 
 938  
 
 939  
         /** Add node value to a node. Distributions for the node assign zero probability
 940  
          * to the new value. Child nodes duplicate CPT conditioned on the new value.
 941  
          * @param nTargetNode index of the node to add value for
 942  
          * @param sNewValue name of the value
 943  
          */
 944  
         public void addNodeValue(int nTargetNode, String sNewValue) {
 945  
                 // update undo stack
 946  0
                 if (m_bNeedsUndoAction) {
 947  0
                         addUndoAction(new AddValueAction(nTargetNode, sNewValue));
 948  
                 }
 949  0
                 Attribute att = m_Instances.attribute(nTargetNode);
 950  0
                 int nCardinality = att.numValues();
 951  0
                 FastVector values = new FastVector(nCardinality);
 952  0
                 for (int iValue = 0; iValue < nCardinality; iValue++) {
 953  0
                         values.addElement(att.value(iValue));
 954  
                 }
 955  0
                 values.addElement(sNewValue);
 956  0
                 replaceAtt(nTargetNode, att.name(), values);
 957  
 
 958  
                 // update distributions of this node
 959  0
                 Estimator[] distributions = m_Distributions[nTargetNode];
 960  0
                 int nNewCard = values.size();
 961  0
                 for (int iParent = 0; iParent < distributions.length; iParent++) {
 962  0
                         DiscreteEstimatorBayes distribution = new DiscreteEstimatorBayes(nNewCard, 0);
 963  0
                         for (int iValue = 0; iValue < nNewCard - 1; iValue++) {
 964  0
                                 distribution.addValue(iValue, distributions[iParent].getProbability(iValue));
 965  
                         }
 966  0
                         distributions[iParent] = distribution;
 967  
                 }
 968  
 
 969  
                 // update distributions of all children
 970  0
                 for (int iNode = 0; iNode < getNrOfNodes(); iNode++) {
 971  0
                         if (m_ParentSets[iNode].contains(nTargetNode)) {
 972  0
                                 distributions = m_Distributions[iNode];
 973  0
                                 ParentSet parentSet = m_ParentSets[iNode];
 974  0
                                 int nParentCard = parentSet.getFreshCardinalityOfParents(m_Instances);
 975  0
                                 Estimator[] newDistributions = new Estimator[nParentCard];
 976  0
                                 int nCard = getCardinality(iNode);
 977  0
                                 int nParents = parentSet.getNrOfParents();
 978  0
                                 int[] values2 = new int[nParents];
 979  0
                                 int iOldPos = 0;
 980  0
                                 int iTargetNode = 0;
 981  0
                                 while (parentSet.getParent(iTargetNode) != nTargetNode) {
 982  0
                                         iTargetNode++;
 983  
                                 }
 984  0
                                 for (int iPos = 0; iPos < nParentCard; iPos++) {
 985  0
                                         DiscreteEstimatorBayes distribution = new DiscreteEstimatorBayes(nCard, 0);
 986  0
                                         for (int iValue = 0; iValue < nCard; iValue++) {
 987  0
                                                 distribution.addValue(iValue, distributions[iOldPos].getProbability(iValue));
 988  
                                         }
 989  0
                                         newDistributions[iPos] = distribution;
 990  
                                         // update values
 991  0
                                         int i = 0;
 992  0
                                         values2[i]++;
 993  0
                                         while (i < nParents && values2[i] == getCardinality(parentSet.getParent(i))) {
 994  0
                                                 values2[i] = 0;
 995  0
                                                 i++;
 996  0
                                                 if (i < nParents) {
 997  0
                                                         values2[i]++;
 998  
                                                 }
 999  
                                         }
 1000  0
                                         if (values2[iTargetNode] != nNewCard - 1) {
 1001  0
                                                 iOldPos++;
 1002  
                                         }
 1003  
                                 }
 1004  0
                                 m_Distributions[iNode] = newDistributions;
 1005  
                         }
 1006  
                 }
 1007  0
         } // addNodeValue
 1008  
 
 1009  
 
 1010  
         /** Delete node value from a node. Distributions for the node are scaled
 1011  
          * up proportional to existing distribution
 1012  
          * (or made uniform if zero probability is assigned to remainder of values).
 1013  
         .* Child nodes delete CPTs conditioned on the new value.
 1014  
          * @param nTargetNode index of the node to delete value from
 1015  
          * @param sValue name of the value to delete
 1016  
          */
 1017  
         public void delNodeValue(int nTargetNode, String sValue) throws Exception {
 1018  
                 // update undo stack
 1019  0
                 if (m_bNeedsUndoAction) {
 1020  0
                         addUndoAction(new DelValueAction(nTargetNode, sValue));
 1021  
                 }
 1022  0
                 Attribute att = m_Instances.attribute(nTargetNode);
 1023  0
                 int nCardinality = att.numValues();
 1024  0
                 FastVector values = new FastVector(nCardinality);
 1025  0
                 int nValue = -1;
 1026  0
                 for (int iValue = 0; iValue < nCardinality; iValue++) {
 1027  0
                         if (att.value(iValue).equals(sValue)) {
 1028  0
                                 nValue = iValue;
 1029  
                         } else {
 1030  0
                                 values.addElement(att.value(iValue));
 1031  
                         }
 1032  
                 }
 1033  0
                 if (nValue < 0) {
 1034  
                         // could not find value
 1035  0
                         throw new Exception("Node " + nTargetNode + " does not have value (" + sValue + ")");
 1036  
                 }
 1037  0
                 replaceAtt(nTargetNode, att.name(), values);
 1038  
 
 1039  
                 // update distributions
 1040  0
                 Estimator[] distributions = m_Distributions[nTargetNode];
 1041  0
                 int nCard = values.size();
 1042  0
                 for (int iParent = 0; iParent < distributions.length; iParent++) {
 1043  0
                         DiscreteEstimatorBayes distribution = new DiscreteEstimatorBayes(nCard, 0);
 1044  0
                         double sum = 0;
 1045  0
                         for (int iValue = 0; iValue < nCard; iValue++) {
 1046  0
                                 sum += distributions[iParent].getProbability(iValue);
 1047  
                         }
 1048  0
                         if (sum > 0) {
 1049  0
                                 for (int iValue = 0; iValue < nCard; iValue++) {
 1050  0
                                         distribution.addValue(iValue, distributions[iParent].getProbability(iValue) / sum);
 1051  
                                 }
 1052  
                         } else {
 1053  0
                                 for (int iValue = 0; iValue < nCard; iValue++) {
 1054  0
                                         distribution.addValue(iValue, 1.0 / nCard);
 1055  
                                 }
 1056  
                         }
 1057  0
                         distributions[iParent] = distribution;
 1058  
                 }
 1059  
 
 1060  
                 // update distributions of all children
 1061  0
                 for (int iNode = 0; iNode < getNrOfNodes(); iNode++) {
 1062  0
                         if (m_ParentSets[iNode].contains(nTargetNode)) {
 1063  0
                                 ParentSet parentSet = m_ParentSets[iNode];
 1064  0
                                 distributions = m_Distributions[iNode];
 1065  0
                                 Estimator[] newDistributions = new Estimator[distributions.length * nCard / (nCard + 1)];
 1066  0
                                 int iCurrentDist = 0;
 1067  
 
 1068  0
                                 int nParents = parentSet.getNrOfParents();
 1069  0
                                 int[] values2 = new int[nParents];
 1070  
                                 // fill in the values
 1071  0
                                 int nParentCard = parentSet.getFreshCardinalityOfParents(m_Instances) * (nCard + 1) / nCard;
 1072  0
                                 int iTargetNode = 0;
 1073  0
                                 while (parentSet.getParent(iTargetNode) != nTargetNode) {
 1074  0
                                         iTargetNode++;
 1075  
                                 }
 1076  0
                                 int[] nCards = new int[nParents];
 1077  0
                                 for (int iParent = 0; iParent < nParents; iParent++) {
 1078  0
                                         nCards[iParent] = getCardinality(parentSet.getParent(iParent));
 1079  
                                 }
 1080  0
                                 nCards[iTargetNode]++;
 1081  0
                                 for (int iPos = 0; iPos < nParentCard; iPos++) {
 1082  0
                                         if (values2[iTargetNode] != nValue) {
 1083  0
                                                 newDistributions[iCurrentDist++] = distributions[iPos];
 1084  
                                         }
 1085  
                                         // update values
 1086  0
                                         int i = 0;
 1087  0
                                         values2[i]++;
 1088  0
                                         while (i < nParents && values2[i] == nCards[i]) {
 1089  0
                                                 values2[i] = 0;
 1090  0
                                                 i++;
 1091  0
                                                 if (i < nParents) {
 1092  0
                                                         values2[i]++;
 1093  
                                                 }
 1094  
                                         }
 1095  
                                 }
 1096  
 
 1097  0
                                 m_Distributions[iNode] = newDistributions;
 1098  
                         }
 1099  
                 }
 1100  
                 // update evidence
 1101  0
                 if (getEvidence(nTargetNode) > nValue) {
 1102  0
                         setEvidence(nTargetNode, getEvidence(nTargetNode) - 1);
 1103  
                 }
 1104  0
         } // delNodeValue
 1105  
 
 1106  
         /** set position of node
 1107  
          * @param iNode index of node to set position for
 1108  
          * @param nX x position of new position
 1109  
          * @param nY y position of new position
 1110  
          */
 1111  
         public void setPosition(int iNode, int nX, int nY) {
 1112  
                 // update undo stack
 1113  0
                 if (m_bNeedsUndoAction) {
 1114  0
                         boolean isUpdate = false;
 1115  0
                         UndoAction undoAction = null;
 1116  
                         try {
 1117  0
                                 if (m_undoStack.size() > 0) {
 1118  0
                                         undoAction = (UndoAction) m_undoStack.elementAt(m_undoStack.size() - 1);
 1119  0
                                         SetPositionAction posAction = (SetPositionAction) undoAction;
 1120  0
                                         if (posAction.m_nTargetNode == iNode) {
 1121  0
                                                 isUpdate = true;
 1122  0
                                                 posAction.setUndoPosition(nX, nY);
 1123  
                                         }
 1124  
                                 }
 1125  0
                         } catch (Exception e) {
 1126  
                                 // ignore. it's not a SetPositionAction
 1127  0
                         }
 1128  0
                         if (!isUpdate) {
 1129  0
                                 addUndoAction(new SetPositionAction(iNode, nX, nY));
 1130  
                         }
 1131  
                 }
 1132  0
                 m_nPositionX.setElementAt(nX, iNode);
 1133  0
                 m_nPositionY.setElementAt(nY, iNode);
 1134  0
         } // setPosition
 1135  
 
 1136  
         /** Set position of node. Move set of nodes with the same displacement
 1137  
          * as a specified node.
 1138  
          * @param nNode index of node to set position for
 1139  
          * @param nX x position of new position
 1140  
          * @param nY y position of new position
 1141  
          * @param nodes array of indexes of nodes to move
 1142  
          */
 1143  
         public void setPosition(int nNode, int nX, int nY, FastVector nodes) {
 1144  0
                 int dX = nX - getPositionX(nNode);
 1145  0
                 int dY = nY - getPositionY(nNode);
 1146  
                 // update undo stack
 1147  0
                 if (m_bNeedsUndoAction) {
 1148  0
                         boolean isUpdate = false;
 1149  
                         try {
 1150  0
                                 UndoAction undoAction = null;
 1151  0
                                 if (m_undoStack.size() > 0) {
 1152  0
                                         undoAction = (UndoAction) m_undoStack.elementAt(m_undoStack.size() - 1);
 1153  0
                                                 SetGroupPositionAction posAction = (SetGroupPositionAction) undoAction;
 1154  0
                                                 isUpdate = true;
 1155  0
                                                 int iNode = 0;
 1156  0
                                                 while (isUpdate && iNode < posAction.m_nodes.size()) {
 1157  0
                                                         if ((Integer)posAction.m_nodes.elementAt(iNode) != (Integer) nodes.elementAt(iNode)) {
 1158  0
                                                                 isUpdate = false;
 1159  
                                                         }
 1160  0
                                                         iNode++;
 1161  
                                                 }
 1162  0
                                                 if (isUpdate == true) {
 1163  0
                                                         posAction.setUndoPosition(dX, dY);
 1164  
                                                 }
 1165  
                                 }
 1166  0
                         } catch (Exception e) {
 1167  
                                 // ignore. it's not a SetPositionAction
 1168  0
                         }
 1169  0
                         if (!isUpdate) {
 1170  0
                                 addUndoAction(new SetGroupPositionAction(nodes, dX, dY));
 1171  
                         }
 1172  
                 }
 1173  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1174  0
                         nNode = (Integer) nodes.elementAt(iNode);
 1175  0
                         m_nPositionX.setElementAt(getPositionX(nNode) + dX, nNode);
 1176  0
                         m_nPositionY.setElementAt(getPositionY(nNode) + dY, nNode);
 1177  
                 }
 1178  0
         } // setPosition
 1179  
 
 1180  
         /** set positions of all nodes
 1181  
          * @param nPosX new x positions for all nodes
 1182  
          * @param nPosY new y positions for all nodes
 1183  
          */
 1184  
         public void layoutGraph(FastVector nPosX, FastVector nPosY) {
 1185  0
                 if (m_bNeedsUndoAction) {
 1186  0
                         addUndoAction(new LayoutGraphAction(nPosX, nPosY));
 1187  
                 }
 1188  0
                 m_nPositionX = nPosX;
 1189  0
                 m_nPositionY = nPosY;
 1190  0
         } // layoutGraph
 1191  
 
 1192  
         /** get x position of a node
 1193  
          * @param iNode index of node of interest
 1194  
          */
 1195  
         public int getPositionX(int iNode) {
 1196  0
                 return (Integer) (m_nPositionX.elementAt(iNode));
 1197  
         }
 1198  
 
 1199  
         /** get y position of a node
 1200  
          * @param iNode index of node of interest
 1201  
          */
 1202  
         public int getPositionY(int iNode) {
 1203  0
                 return (Integer) (m_nPositionY.elementAt(iNode));
 1204  
         }
 1205  
 
 1206  
         /** align set of nodes with the left most node in the list
 1207  
          * @param nodes list of indexes of nodes to align
 1208  
          */
 1209  
         public void alignLeft(FastVector nodes) {
 1210  
                 // update undo stack
 1211  0
                 if (m_bNeedsUndoAction) {
 1212  0
                         addUndoAction(new alignLeftAction(nodes));
 1213  
                 }
 1214  0
                 int nMinX = -1;
 1215  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1216  0
                         int nX = getPositionX((Integer) nodes.elementAt(iNode));
 1217  0
                         if (nX < nMinX || iNode == 0) {
 1218  0
                                 nMinX = nX;
 1219  
                         }
 1220  
                 }
 1221  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1222  0
                         int nNode = (Integer) nodes.elementAt(iNode);
 1223  0
                         m_nPositionX.setElementAt(nMinX, nNode);
 1224  
                 }
 1225  0
         } // alignLeft
 1226  
 
 1227  
         /** align set of nodes with the right most node in the list
 1228  
          * @param nodes list of indexes of nodes to align
 1229  
          */
 1230  
         public void alignRight(FastVector nodes) {
 1231  
                 // update undo stack
 1232  0
                 if (m_bNeedsUndoAction) {
 1233  0
                         addUndoAction(new alignRightAction(nodes));
 1234  
                 }
 1235  0
                 int nMaxX = -1;
 1236  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1237  0
                         int nX = getPositionX((Integer) nodes.elementAt(iNode));
 1238  0
                         if (nX > nMaxX || iNode == 0) {
 1239  0
                                 nMaxX = nX;
 1240  
                         }
 1241  
                 }
 1242  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1243  0
                         int nNode = (Integer) nodes.elementAt(iNode);
 1244  0
                         m_nPositionX.setElementAt(nMaxX, nNode);
 1245  
                 }
 1246  0
         } // alignRight
 1247  
 
 1248  
         /** align set of nodes with the top most node in the list
 1249  
          * @param nodes list of indexes of nodes to align
 1250  
          */
 1251  
         public void alignTop(FastVector nodes) {
 1252  
                 // update undo stack
 1253  0
                 if (m_bNeedsUndoAction) {
 1254  0
                         addUndoAction(new alignTopAction(nodes));
 1255  
                 }
 1256  0
                 int nMinY = -1;
 1257  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1258  0
                         int nY = getPositionY((Integer) nodes.elementAt(iNode));
 1259  0
                         if (nY < nMinY || iNode == 0) {
 1260  0
                                 nMinY = nY;
 1261  
                         }
 1262  
                 }
 1263  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1264  0
                         int nNode = (Integer) nodes.elementAt(iNode);
 1265  0
                         m_nPositionY.setElementAt(nMinY, nNode);
 1266  
                 }
 1267  0
         } // alignTop
 1268  
 
 1269  
         /** align set of nodes with the bottom most node in the list
 1270  
          * @param nodes list of indexes of nodes to align
 1271  
          */
 1272  
         public void alignBottom(FastVector nodes) {
 1273  
                 // update undo stack
 1274  0
                 if (m_bNeedsUndoAction) {
 1275  0
                         addUndoAction(new alignBottomAction(nodes));
 1276  
                 }
 1277  0
                 int nMaxY = -1;
 1278  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1279  0
                         int nY = getPositionY((Integer) nodes.elementAt(iNode));
 1280  0
                         if (nY > nMaxY || iNode == 0) {
 1281  0
                                 nMaxY = nY;
 1282  
                         }
 1283  
                 }
 1284  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1285  0
                         int nNode = (Integer) nodes.elementAt(iNode);
 1286  0
                         m_nPositionY.setElementAt(nMaxY, nNode);
 1287  
                 }
 1288  0
         } // alignBottom
 1289  
 
 1290  
         /** center set of nodes half way between left and right most node in the list
 1291  
          * @param nodes list of indexes of nodes to center
 1292  
          */
 1293  
         public void centerHorizontal(FastVector nodes) {
 1294  
                 // update undo stack
 1295  0
                 if (m_bNeedsUndoAction) {
 1296  0
                         addUndoAction(new centerHorizontalAction(nodes));
 1297  
                 }
 1298  0
                 int nMinY = -1;
 1299  0
                 int nMaxY = -1;
 1300  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1301  0
                         int nY = getPositionY((Integer) nodes.elementAt(iNode));
 1302  0
                         if (nY < nMinY || iNode == 0) {
 1303  0
                                 nMinY = nY;
 1304  
                         }
 1305  0
                         if (nY > nMaxY || iNode == 0) {
 1306  0
                                 nMaxY = nY;
 1307  
                         }
 1308  
                 }
 1309  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1310  0
                         int nNode = (Integer) nodes.elementAt(iNode);
 1311  0
                         m_nPositionY.setElementAt((nMinY + nMaxY) / 2, nNode);
 1312  
                 }
 1313  0
         } // centerHorizontal
 1314  
 
 1315  
         /** center set of nodes half way between top and bottom most node in the list
 1316  
          * @param nodes list of indexes of nodes to center
 1317  
          */
 1318  
         public void centerVertical(FastVector nodes) {
 1319  
                 // update undo stack
 1320  0
                 if (m_bNeedsUndoAction) {
 1321  0
                         addUndoAction(new centerVerticalAction(nodes));
 1322  
                 }
 1323  0
                 int nMinX = -1;
 1324  0
                 int nMaxX = -1;
 1325  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1326  0
                         int nX = getPositionX((Integer) nodes.elementAt(iNode));
 1327  0
                         if (nX < nMinX || iNode == 0) {
 1328  0
                                 nMinX = nX;
 1329  
                         }
 1330  0
                         if (nX > nMaxX || iNode == 0) {
 1331  0
                                 nMaxX = nX;
 1332  
                         }
 1333  
                 }
 1334  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1335  0
                         int nNode = (Integer) nodes.elementAt(iNode);
 1336  0
                         m_nPositionX.setElementAt((nMinX + nMaxX) / 2, nNode);
 1337  
                 }
 1338  0
         } // centerVertical
 1339  
 
 1340  
         /** space out set of nodes evenly between left and right most node in the list
 1341  
          * @param nodes list of indexes of nodes to space out
 1342  
          */
 1343  
         public void spaceHorizontal(FastVector nodes) {
 1344  
                 // update undo stack
 1345  0
                 if (m_bNeedsUndoAction) {
 1346  0
                         addUndoAction(new spaceHorizontalAction(nodes));
 1347  
                 }
 1348  0
                 int nMinX = -1;
 1349  0
                 int nMaxX = -1;
 1350  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1351  0
                         int nX = getPositionX((Integer) nodes.elementAt(iNode));
 1352  0
                         if (nX < nMinX || iNode == 0) {
 1353  0
                                 nMinX = nX;
 1354  
                         }
 1355  0
                         if (nX > nMaxX || iNode == 0) {
 1356  0
                                 nMaxX = nX;
 1357  
                         }
 1358  
                 }
 1359  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1360  0
                         int nNode = (Integer) nodes.elementAt(iNode);
 1361  0
                         m_nPositionX.setElementAt((int) (nMinX + iNode * (nMaxX - nMinX) / (nodes.size() - 1.0)), nNode);
 1362  
                 }
 1363  0
         } // spaceHorizontal
 1364  
 
 1365  
         /** space out set of nodes evenly between top and bottom most node in the list
 1366  
          * @param nodes list of indexes of nodes to space out
 1367  
          */
 1368  
         public void spaceVertical(FastVector nodes) {
 1369  
                 // update undo stack
 1370  0
                 if (m_bNeedsUndoAction) {
 1371  0
                         addUndoAction(new spaceVerticalAction(nodes));
 1372  
                 }
 1373  0
                 int nMinY = -1;
 1374  0
                 int nMaxY = -1;
 1375  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1376  0
                         int nY = getPositionY((Integer) nodes.elementAt(iNode));
 1377  0
                         if (nY < nMinY || iNode == 0) {
 1378  0
                                 nMinY = nY;
 1379  
                         }
 1380  0
                         if (nY > nMaxY || iNode == 0) {
 1381  0
                                 nMaxY = nY;
 1382  
                         }
 1383  
                 }
 1384  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1385  0
                         int nNode = (Integer) nodes.elementAt(iNode);
 1386  0
                         m_nPositionY.setElementAt((int) (nMinY + iNode * (nMaxY - nMinY) / (nodes.size() - 1.0)), nNode);
 1387  
                 }
 1388  0
         } // spaceVertical
 1389  
 
 1390  
 
 1391  
         /** replace attribute with specified name and values
 1392  
          * @param nTargetNode index of node the replace specification for
 1393  
          * @param sName new name of the node
 1394  
          * @param values array of values of the node
 1395  
          */
 1396  
         void replaceAtt(int nTargetNode, String sName, FastVector values) {
 1397  0
                 Attribute newAtt = new Attribute(sName, values);
 1398  0
                 if (m_Instances.classIndex() == nTargetNode) {
 1399  0
                         m_Instances.setClassIndex(-1);
 1400  
                         /*m_Instances.insertAttributeAt(newAtt, nTargetNode);
 1401  
                         m_Instances.deleteAttributeAt(nTargetNode + 1);
 1402  
                         m_Instances.setClassIndex(nTargetNode); */
 1403  
                         
 1404  0
                         m_Instances.deleteAttributeAt(nTargetNode);
 1405  0
                         m_Instances.insertAttributeAt(newAtt, nTargetNode);
 1406  0
                         m_Instances.setClassIndex(nTargetNode);
 1407  
                 } else {
 1408  
                         /*m_Instances.insertAttributeAt(newAtt, nTargetNode);
 1409  
                         m_Instances.deleteAttributeAt(nTargetNode + 1); */
 1410  0
                         m_Instances.deleteAttributeAt(nTargetNode);
 1411  0
                         m_Instances.insertAttributeAt(newAtt, nTargetNode);
 1412  
                 }
 1413  0
         } // replaceAtt
 1414  
 
 1415  
         /** return marginal distibution for a node
 1416  
          * @param iNode index of node of interest
 1417  
          */
 1418  
         public double[] getMargin(int iNode) {
 1419  0
                 return (double[]) m_fMarginP.elementAt(iNode);
 1420  
         };
 1421  
 
 1422  
         /** set marginal distibution for a node
 1423  
          * @param iNode index of node to set marginal distribution for
 1424  
          * @param fMarginP marginal distribution
 1425  
          */
 1426  
         public void setMargin(int iNode, double[] fMarginP) {
 1427  0
                 m_fMarginP.setElementAt(fMarginP, iNode);
 1428  0
         }
 1429  
 
 1430  
         /** get evidence state of a node. -1 represents no evidence set, otherwise
 1431  
          * the index of a value of the node
 1432  
          * @param iNode index of node of interest
 1433  
          */
 1434  
         public int getEvidence(int iNode) {
 1435  0
                 return (Integer) m_nEvidence.elementAt(iNode);
 1436  
         }
 1437  
 
 1438  
         /** set evidence state of a node. -1 represents no evidence set, otherwise
 1439  
          * the index of a value of the node
 1440  
           * @param iNode index of node of interest
 1441  
          * @param iValue evidence value to set
 1442  
          */
 1443  
         public void setEvidence(int iNode, int iValue) {
 1444  0
                 m_nEvidence.setElementAt(iValue, iNode);
 1445  0
         }
 1446  
 
 1447  
         /** return list of children of a node
 1448  
          * @param nTargetNode index of node of interest
 1449  
          */
 1450  
         public FastVector getChildren(int nTargetNode) {
 1451  0
                 FastVector children = new FastVector();
 1452  0
                 for (int iNode = 0; iNode < getNrOfNodes(); iNode++) {
 1453  0
                         if (m_ParentSets[iNode].contains(nTargetNode)) {
 1454  0
                                 children.addElement(iNode);
 1455  
                         }
 1456  
                 }
 1457  0
                 return children;
 1458  
         } // getChildren
 1459  
 
 1460  
         /** returns network in XMLBIF format
 1461  
         */
 1462  
         public String toXMLBIF03() {
 1463  0
                 if (m_Instances == null) {
 1464  0
                         return ("<!--No model built yet-->");
 1465  
                 }
 1466  
 
 1467  0
                 StringBuffer text = new StringBuffer();
 1468  0
                 text.append(getBIFHeader());
 1469  0
                 text.append("\n");
 1470  0
                 text.append("\n");
 1471  0
                 text.append("<BIF VERSION=\"0.3\">\n");
 1472  0
                 text.append("<NETWORK>\n");
 1473  0
                 text.append("<NAME>" + XMLNormalize(m_Instances.relationName()) + "</NAME>\n");
 1474  0
                 for (int iAttribute = 0; iAttribute < m_Instances.numAttributes(); iAttribute++) {
 1475  0
                         text.append("<VARIABLE TYPE=\"nature\">\n");
 1476  0
                         text.append("<NAME>" + XMLNormalize(m_Instances.attribute(iAttribute).name()) + "</NAME>\n");
 1477  0
                         for (int iValue = 0; iValue < m_Instances.attribute(iAttribute).numValues(); iValue++) {
 1478  0
                                 text.append("<OUTCOME>" + XMLNormalize(m_Instances.attribute(iAttribute).value(iValue))
 1479  
                                                 + "</OUTCOME>\n");
 1480  
                         }
 1481  0
                         text.append("<PROPERTY>position = (" + getPositionX(iAttribute) + "," + getPositionY(iAttribute)
 1482  
                                         + ")</PROPERTY>\n");
 1483  0
                         text.append("</VARIABLE>\n");
 1484  
                 }
 1485  
 
 1486  0
                 for (int iAttribute = 0; iAttribute < m_Instances.numAttributes(); iAttribute++) {
 1487  0
                         text.append("<DEFINITION>\n");
 1488  0
                         text.append("<FOR>" + XMLNormalize(m_Instances.attribute(iAttribute).name()) + "</FOR>\n");
 1489  0
                         for (int iParent = 0; iParent < m_ParentSets[iAttribute].getNrOfParents(); iParent++) {
 1490  0
                                 text.append("<GIVEN>"
 1491  
                                                 + XMLNormalize(m_Instances.attribute(m_ParentSets[iAttribute].getParent(iParent)).name())
 1492  
                                                 + "</GIVEN>\n");
 1493  
                         }
 1494  0
                         text.append("<TABLE>\n");
 1495  0
                         for (int iParent = 0; iParent < m_ParentSets[iAttribute].getCardinalityOfParents(); iParent++) {
 1496  0
                                 for (int iValue = 0; iValue < m_Instances.attribute(iAttribute).numValues(); iValue++) {
 1497  0
                                         text.append(m_Distributions[iAttribute][iParent].getProbability(iValue));
 1498  0
                                         text.append(' ');
 1499  
                                 }
 1500  0
                                 text.append('\n');
 1501  
                         }
 1502  0
                         text.append("</TABLE>\n");
 1503  0
                         text.append("</DEFINITION>\n");
 1504  
                 }
 1505  0
                 text.append("</NETWORK>\n");
 1506  0
                 text.append("</BIF>\n");
 1507  0
                 return text.toString();
 1508  
         } // toXMLBIF03
 1509  
 
 1510  
         /** return fragment of network in XMLBIF format
 1511  
          * @param nodes array of indexes of nodes that should be in the fragment
 1512  
          */
 1513  
         public String toXMLBIF03(FastVector nodes) {
 1514  0
                 StringBuffer text = new StringBuffer();
 1515  0
                 text.append(getBIFHeader());
 1516  0
                 text.append("\n");
 1517  0
                 text.append("\n");
 1518  0
                 text.append("<BIF VERSION=\"0.3\">\n");
 1519  0
                 text.append("<NETWORK>\n");
 1520  0
                 text.append("<NAME>" + XMLNormalize(m_Instances.relationName()) + "</NAME>\n");
 1521  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1522  0
                         int nNode = (Integer) nodes.elementAt(iNode);
 1523  0
                         text.append("<VARIABLE TYPE=\"nature\">\n");
 1524  0
                         text.append("<NAME>" + XMLNormalize(m_Instances.attribute(nNode).name()) + "</NAME>\n");
 1525  0
                         for (int iValue = 0; iValue < m_Instances.attribute(nNode).numValues(); iValue++) {
 1526  0
                                 text.append("<OUTCOME>" + XMLNormalize(m_Instances.attribute(nNode).value(iValue)) + "</OUTCOME>\n");
 1527  
                         }
 1528  0
                         text.append("<PROPERTY>position = (" + getPositionX(nNode) + "," + getPositionY(nNode) + ")</PROPERTY>\n");
 1529  0
                         text.append("</VARIABLE>\n");
 1530  
                 }
 1531  
 
 1532  0
                 for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1533  0
                         int nNode = (Integer) nodes.elementAt(iNode);
 1534  0
                         text.append("<DEFINITION>\n");
 1535  0
                         text.append("<FOR>" + XMLNormalize(m_Instances.attribute(nNode).name()) + "</FOR>\n");
 1536  0
                         for (int iParent = 0; iParent < m_ParentSets[nNode].getNrOfParents(); iParent++) {
 1537  0
                                 text.append("<GIVEN>"
 1538  
                                                 + XMLNormalize(m_Instances.attribute(m_ParentSets[nNode].getParent(iParent)).name())
 1539  
                                                 + "</GIVEN>\n");
 1540  
                         }
 1541  0
                         text.append("<TABLE>\n");
 1542  0
                         for (int iParent = 0; iParent < m_ParentSets[nNode].getCardinalityOfParents(); iParent++) {
 1543  0
                                 for (int iValue = 0; iValue < m_Instances.attribute(nNode).numValues(); iValue++) {
 1544  0
                                         text.append(m_Distributions[nNode][iParent].getProbability(iValue));
 1545  0
                                         text.append(' ');
 1546  
                                 }
 1547  0
                                 text.append('\n');
 1548  
                         }
 1549  0
                         text.append("</TABLE>\n");
 1550  0
                         text.append("</DEFINITION>\n");
 1551  
                 }
 1552  0
                 text.append("</NETWORK>\n");
 1553  0
                 text.append("</BIF>\n");
 1554  0
                 return text.toString();
 1555  
         } // toXMLBIF03
 1556  
 
 1557  
         /** undo stack for undoin edit actions, or redo edit actions */
 1558  0
         FastVector m_undoStack = new FastVector();
 1559  
 
 1560  
         /** current action in undo stack */
 1561  0
         int m_nCurrentEditAction = -1;
 1562  
 
 1563  
         /** action that the network is saved */
 1564  0
         int m_nSavedPointer = -1;
 1565  
 
 1566  
         /***************************************************************************
 1567  
          * flag to indicate whether an edit action needs to introduce an undo
 1568  
          * action. This is only false when an undo or redo action is performed.
 1569  
          **************************************************************************/
 1570  0
         boolean m_bNeedsUndoAction = true;
 1571  
 
 1572  
         /** return whether there is something on the undo stack that can be performed */
 1573  
         public boolean canUndo() {
 1574  0
                 return m_nCurrentEditAction >= 0;
 1575  
         }
 1576  
 
 1577  
         /** return whether there is something on the undo stack that can be performed */
 1578  
         public boolean canRedo() {
 1579  0
                 return m_nCurrentEditAction < m_undoStack.size() - 1;
 1580  
         }
 1581  
 
 1582  
         /** return true when current state differs from the state the network was last saved */
 1583  
         public boolean isChanged() {
 1584  0
                 return m_nCurrentEditAction != m_nSavedPointer;
 1585  
         }
 1586  
 
 1587  
         /** indicate the network state was saved */
 1588  
         public void isSaved() {
 1589  0
                 m_nSavedPointer = m_nCurrentEditAction;
 1590  0
         }
 1591  
 
 1592  
         /** get message representing the last action performed on the network */
 1593  
         public String lastActionMsg() {
 1594  0
                 if (m_undoStack.size() == 0) {
 1595  0
                         return "";
 1596  
                 }
 1597  0
                 return ((UndoAction) m_undoStack.lastElement()).getRedoMsg();
 1598  
         } // lastActionMsg
 1599  
 
 1600  
 
 1601  
         /** undo the last edit action performed on the network.
 1602  
          * returns message representing the action performed.
 1603  
          */
 1604  
         public String undo() {
 1605  0
                 if (!canUndo()) {
 1606  0
                         return "";
 1607  
                 }
 1608  0
                 UndoAction undoAction = (UndoAction) m_undoStack.elementAt(m_nCurrentEditAction);
 1609  0
                 m_bNeedsUndoAction = false;
 1610  0
                 undoAction.undo();
 1611  0
                 m_bNeedsUndoAction = true;
 1612  0
                 m_nCurrentEditAction--;
 1613  
 
 1614  
                 // undo stack debugging
 1615  
                 /*
 1616  
                 if (m_nCurrentEditAction>0) {
 1617  
                         String sXML = (String) m_sXMLStack.elementAt(m_nCurrentEditAction);
 1618  
                         String sXMLCurrent = toXMLBIF03();
 1619  
                         if (!sXML.equals(sXMLCurrent)) {
 1620  
                                 String sDiff = "";
 1621  
                                 String sDiff2 = "";
 1622  
                                 for (int i = 0; i < sXML.length() && sDiff.length() < 80; i++) {
 1623  
                                         if (sXML.charAt(i) != sXMLCurrent.charAt(i)) {
 1624  
                                                 sDiff += sXML.charAt(i);
 1625  
                                                 sDiff2 += sXMLCurrent.charAt(i);
 1626  
                                         }
 1627  
                                 }
 1628  
 
 1629  
                                 JOptionPane.showMessageDialog(null,"Undo error\n" + sDiff + " \n" + sDiff2);
 1630  
                         }
 1631  
                 }
 1632  
                 */
 1633  0
                 return undoAction.getUndoMsg();
 1634  
         } // undo
 1635  
 
 1636  
         /** redo the last edit action performed on the network.
 1637  
          * returns message representing the action performed.
 1638  
          */
 1639  
         public String redo() {
 1640  0
                 if (!canRedo()) {
 1641  0
                         return "";
 1642  
                 }
 1643  0
                 m_nCurrentEditAction++;
 1644  0
                 UndoAction undoAction = (UndoAction) m_undoStack.elementAt(m_nCurrentEditAction);
 1645  0
                 m_bNeedsUndoAction = false;
 1646  0
                 undoAction.redo();
 1647  0
                 m_bNeedsUndoAction = true;
 1648  
 
 1649  
                 // undo stack debugging
 1650  
                 /*
 1651  
                 if (m_nCurrentEditAction < m_sXMLStack.size()) {
 1652  
                         String sXML = (String) m_sXMLStack.elementAt(m_nCurrentEditAction);
 1653  
                         String sXMLCurrent = toXMLBIF03();
 1654  
                         if (!sXML.equals(sXMLCurrent)) {
 1655  
                                 String sDiff = "";
 1656  
                                 String sDiff2 = "";
 1657  
                                 for (int i = 0; i < sXML.length() && sDiff.length() < 80; i++) {
 1658  
                                         if (sXML.charAt(i) != sXMLCurrent.charAt(i)) {
 1659  
                                                 sDiff += sXML.charAt(i);
 1660  
                                                 sDiff2 += sXMLCurrent.charAt(i);
 1661  
                                         }
 1662  
                                 }
 1663  
 
 1664  
                                 JOptionPane.showMessageDialog(null,"redo error\n" + sDiff + " \n" + sDiff2);
 1665  
                         }
 1666  
                 }
 1667  
                 */
 1668  0
                 return undoAction.getRedoMsg();
 1669  
         } // redo
 1670  
 
 1671  
         /** add undo action to the undo stack.
 1672  
          * @param action operation that needs to be added to the undo stack
 1673  
          */
 1674  
         void addUndoAction(UndoAction action) {
 1675  0
                 int iAction = m_undoStack.size() - 1;
 1676  0
                 while (iAction > m_nCurrentEditAction) {
 1677  0
                         m_undoStack.removeElementAt(iAction--);
 1678  
                 }
 1679  0
                 if (m_nSavedPointer > m_nCurrentEditAction) {
 1680  0
                         m_nSavedPointer = -2;
 1681  
                 }
 1682  0
                 m_undoStack.addElement(action);
 1683  
                 //m_sXMLStack.addElement(toXMLBIF03());
 1684  0
                 m_nCurrentEditAction++;
 1685  0
         } // addUndoAction
 1686  
 
 1687  
         /** remove all actions from the undo stack */
 1688  
         public void clearUndoStack() {
 1689  0
                 m_undoStack = new FastVector();
 1690  
                 //m_sXMLStack = new FastVector();
 1691  0
                 m_nCurrentEditAction = -1;
 1692  0
                 m_nSavedPointer = -1;
 1693  0
         } // clearUndoStack
 1694  
 
 1695  
         /** base class for actions representing operations on the Bayesian network
 1696  
          * that can be undone/redone
 1697  
          */
 1698  0
         class UndoAction implements Serializable {
 1699  
                 /** for serialization */
 1700  
                 static final long serialVersionUID = 1;
 1701  
                 public void undo() {
 1702  0
                 }
 1703  
 
 1704  
                 public void redo() {
 1705  0
                 }
 1706  
 
 1707  
                 public String getUndoMsg() {
 1708  0
                         return getMsg();
 1709  
                 }
 1710  
 
 1711  
                 public String getRedoMsg() {
 1712  0
                         return getMsg();
 1713  
                 }
 1714  
                 String getMsg() {
 1715  0
                         String sStr = toString();
 1716  0
                         int iStart = sStr.indexOf('$');
 1717  0
                         int iEnd = sStr.indexOf('@');
 1718  0
                         StringBuffer sBuffer = new StringBuffer();
 1719  0
                         for(int i= iStart + 1; i < iEnd; i++) {
 1720  0
                                 char c = sStr.charAt(i);
 1721  0
                                 if (Character.isUpperCase(c)) {
 1722  0
                                         sBuffer.append(' ');
 1723  
                                 }
 1724  0
                                 sBuffer.append(sStr.charAt(i));
 1725  
                         }
 1726  0
                         return sBuffer.toString();
 1727  
                 } // getMsg
 1728  
         } // class UndoAction
 1729  
 
 1730  
         class AddNodeAction extends UndoAction {
 1731  
                 /** for serialization */
 1732  
                 static final long serialVersionUID = 1;
 1733  
                 String m_sName;
 1734  
                 int m_nPosX;
 1735  
                 int m_nPosY;
 1736  
 
 1737  
                 int m_nCardinality;
 1738  
 
 1739  0
                 AddNodeAction(String sName, int nCardinality, int nPosX, int nPosY) {
 1740  0
                         m_sName = sName;
 1741  0
                         m_nCardinality = nCardinality;
 1742  0
                         m_nPosX = nPosX;
 1743  0
                         m_nPosY = nPosY;
 1744  0
                 } // c'tor
 1745  
 
 1746  
                 public void undo() {
 1747  
                         try {
 1748  0
                                 deleteNode(getNrOfNodes() - 1);
 1749  0
                         } catch (Exception e) {
 1750  0
                                 e.printStackTrace();
 1751  0
                         }
 1752  0
                 } // undo
 1753  
 
 1754  
                 public void redo() {
 1755  
                         try {
 1756  0
                                 addNode(m_sName, m_nCardinality, m_nPosX, m_nPosY);
 1757  0
                         } catch (Exception e) {
 1758  0
                                 e.printStackTrace();
 1759  0
                         }
 1760  0
                 } // redo
 1761  
         } // class AddNodeAction
 1762  
 
 1763  
         class DeleteNodeAction extends UndoAction {
 1764  
                 /** for serialization */
 1765  
                 static final long serialVersionUID = 1;
 1766  
                 int m_nTargetNode;
 1767  
 
 1768  
                 Attribute m_att;
 1769  
 
 1770  
                 Estimator[] m_CPT;
 1771  
 
 1772  
                 ParentSet m_ParentSet;
 1773  
 
 1774  
                 FastVector m_deleteArcActions;
 1775  
 
 1776  
                 int m_nPosX;
 1777  
 
 1778  
                 int m_nPosY;
 1779  
 
 1780  0
                 DeleteNodeAction(int nTargetNode) {
 1781  0
                         m_nTargetNode = nTargetNode;
 1782  0
                         m_att = m_Instances.attribute(nTargetNode);
 1783  
                         try {
 1784  0
                                 SerializedObject so = new SerializedObject(m_Distributions[nTargetNode]);
 1785  0
                                 m_CPT = (Estimator[]) so.getObject();
 1786  
                                 ;
 1787  0
                                 so = new SerializedObject(m_ParentSets[nTargetNode]);
 1788  0
                                 m_ParentSet = (ParentSet) so.getObject();
 1789  0
                         } catch (Exception e) {
 1790  0
                                 e.printStackTrace();
 1791  0
                         }
 1792  0
                         m_deleteArcActions = new FastVector();
 1793  0
                         for (int iNode = 0; iNode < getNrOfNodes(); iNode++) {
 1794  0
                                 if (m_ParentSets[iNode].contains(nTargetNode)) {
 1795  0
                                         m_deleteArcActions.addElement(new DeleteArcAction(nTargetNode, iNode));
 1796  
                                 }
 1797  
                         }
 1798  0
                         m_nPosX = getPositionX(m_nTargetNode);
 1799  0
                         m_nPosY = getPositionY(m_nTargetNode);
 1800  0
                 } // c'tor
 1801  
 
 1802  
                 public void undo() {
 1803  
                         try {
 1804  0
                                 m_Instances.insertAttributeAt(m_att, m_nTargetNode);
 1805  0
                                 int nAtts = m_Instances.numAttributes();
 1806  
                                 // update parentsets
 1807  0
                                 ParentSet[] parentSets = new ParentSet[nAtts];
 1808  0
                                 int nX = 0;
 1809  0
                                 for (int iParentSet = 0; iParentSet < nAtts; iParentSet++) {
 1810  0
                                         if (iParentSet == m_nTargetNode) {
 1811  0
                                                 SerializedObject so = new SerializedObject(m_ParentSet);
 1812  0
                                                 parentSets[iParentSet] = (ParentSet) so.getObject();
 1813  0
                                                 nX = 1;
 1814  0
                                         } else {
 1815  0
                                                 parentSets[iParentSet] = m_ParentSets[iParentSet - nX];
 1816  0
                                                 for (int iParent = 0; iParent < parentSets[iParentSet].getNrOfParents(); iParent++) {
 1817  0
                                                         int nParent = parentSets[iParentSet].getParent(iParent);
 1818  0
                                                         if (nParent >= m_nTargetNode) {
 1819  0
                                                                 parentSets[iParentSet].SetParent(iParent, nParent + 1);
 1820  
                                                         }
 1821  
                                                 }
 1822  
                                         }
 1823  
                                 }
 1824  0
                                 m_ParentSets = parentSets;
 1825  
                                 // update distributions
 1826  0
                                 Estimator[][] distributions = new Estimator[nAtts][];
 1827  0
                                 nX = 0;
 1828  0
                                 for (int iNode = 0; iNode < nAtts; iNode++) {
 1829  0
                                         if (iNode == m_nTargetNode) {
 1830  0
                                                 SerializedObject so = new SerializedObject(m_CPT);
 1831  0
                                                 distributions[iNode] = (Estimator[]) so.getObject();
 1832  0
                                                 nX = 1;
 1833  0
                                         } else {
 1834  0
                                                 distributions[iNode] = m_Distributions[iNode - nX];
 1835  
                                         }
 1836  
                                 }
 1837  0
                                 m_Distributions = distributions;
 1838  
 
 1839  0
                                 for (int deletedArc = 0; deletedArc < m_deleteArcActions.size(); deletedArc++) {
 1840  0
                                         DeleteArcAction action = (DeleteArcAction) m_deleteArcActions.elementAt(deletedArc);
 1841  0
                                         action.undo();
 1842  
                                 }
 1843  0
                                 m_nPositionX.insertElementAt(m_nPosX, m_nTargetNode);
 1844  0
                                 m_nPositionY.insertElementAt(m_nPosY, m_nTargetNode);
 1845  0
                                 m_nEvidence.insertElementAt(-1, m_nTargetNode);
 1846  0
                                 m_fMarginP.insertElementAt(new double[getCardinality(m_nTargetNode)], m_nTargetNode);
 1847  0
                         } catch (Exception e) {
 1848  0
                                 e.printStackTrace();
 1849  0
                         }
 1850  0
                 } // undo
 1851  
 
 1852  
                 public void redo() {
 1853  
                         try {
 1854  0
                                 deleteNode(m_nTargetNode);
 1855  0
                         } catch (Exception e) {
 1856  0
                                 e.printStackTrace();
 1857  0
                         }
 1858  0
                 } // redo
 1859  
         } // class DeleteNodeAction
 1860  
 
 1861  
         class DeleteSelectionAction extends UndoAction {
 1862  
                 /** for serialization */
 1863  
                 static final long serialVersionUID = 1;
 1864  
                 FastVector m_nodes;
 1865  
 
 1866  
                 Attribute[] m_att;
 1867  
 
 1868  
                 Estimator[][] m_CPT;
 1869  
 
 1870  
                 ParentSet[] m_ParentSet;
 1871  
 
 1872  
                 FastVector m_deleteArcActions;
 1873  
 
 1874  
                 int[] m_nPosX;
 1875  
 
 1876  
                 int[] m_nPosY;
 1877  
 
 1878  0
                 public DeleteSelectionAction(FastVector nodes) {
 1879  0
                         m_nodes = new FastVector();
 1880  0
                         int nNodes = nodes.size();
 1881  0
                         m_att = new Attribute[nNodes];
 1882  0
                         m_CPT = new Estimator[nNodes][];
 1883  0
                         m_ParentSet = new ParentSet[nNodes];
 1884  0
                         m_nPosX = new int[nNodes];
 1885  0
                         m_nPosY = new int[nNodes];
 1886  0
                         m_deleteArcActions = new FastVector();
 1887  0
                         for (int iNode = 0; iNode < nodes.size(); iNode++) {
 1888  0
                                 int nTargetNode = (Integer) nodes.elementAt(iNode);
 1889  0
                                 m_nodes.addElement(nTargetNode);
 1890  0
                                 m_att[iNode] = m_Instances.attribute(nTargetNode);
 1891  
                                 try {
 1892  0
                                         SerializedObject so = new SerializedObject(m_Distributions[nTargetNode]);
 1893  0
                                         m_CPT[iNode] = (Estimator[]) so.getObject();
 1894  
                                         ;
 1895  0
                                         so = new SerializedObject(m_ParentSets[nTargetNode]);
 1896  0
                                         m_ParentSet[iNode] = (ParentSet) so.getObject();
 1897  0
                                 } catch (Exception e) {
 1898  0
                                         e.printStackTrace();
 1899  0
                                 }
 1900  0
                                 m_nPosX[iNode] = getPositionX(nTargetNode);
 1901  0
                                 m_nPosY[iNode] = getPositionY(nTargetNode);
 1902  0
                                 for (int iNode2 = 0; iNode2 < getNrOfNodes(); iNode2++) {
 1903  0
                                         if (!nodes.contains(iNode2) && m_ParentSets[iNode2].contains(nTargetNode)) {
 1904  0
                                                 m_deleteArcActions.addElement(new DeleteArcAction(nTargetNode, iNode2));
 1905  
                                         }
 1906  
                                 }
 1907  
                         }
 1908  0
                 } // c'tor
 1909  
 
 1910  
                 public void undo() {
 1911  
                         try {
 1912  0
                                 for (int iNode = 0; iNode < m_nodes.size(); iNode++) {
 1913  0
                                         int nTargetNode = (Integer) m_nodes.elementAt(iNode);
 1914  0
                                         m_Instances.insertAttributeAt(m_att[iNode], nTargetNode);
 1915  
                                 }
 1916  0
                                 int nAtts = m_Instances.numAttributes();
 1917  
                                 // update parentsets
 1918  0
                                 ParentSet[] parentSets = new ParentSet[nAtts];
 1919  0
                                 int[] offset = new int[nAtts];
 1920  0
                                 for (int iNode = 0; iNode < nAtts; iNode++) {
 1921  0
                                         offset[iNode] = iNode;
 1922  
                                 }
 1923  0
                                 for (int iNode = m_nodes.size() - 1; iNode >= 0; iNode--) {
 1924  0
                                         int nTargetNode = (Integer) m_nodes.elementAt(iNode);
 1925  0
                                         for (int i = nTargetNode; i < nAtts - 1; i++) {
 1926  0
                                                 offset[i] = offset[i + 1];
 1927  
                                         }
 1928  
                                 }
 1929  
 
 1930  0
                                 int iTargetNode = 0;
 1931  0
                                 for (int iParentSet = 0; iParentSet < nAtts; iParentSet++) {
 1932  0
                                         if (iTargetNode < m_nodes.size()
 1933  
                                                         && (Integer) m_nodes.elementAt(iTargetNode) == (Integer) iParentSet) {
 1934  0
                                                 SerializedObject so = new SerializedObject(m_ParentSet[iTargetNode]);
 1935  0
                                                 parentSets[iParentSet] = (ParentSet) so.getObject();
 1936  0
                                                 iTargetNode++;
 1937  0
                                         } else {
 1938  0
                                                 parentSets[iParentSet] = m_ParentSets[iParentSet - iTargetNode];
 1939  0
                                                 for (int iParent = 0; iParent < parentSets[iParentSet].getNrOfParents(); iParent++) {
 1940  0
                                                         int nParent = parentSets[iParentSet].getParent(iParent);
 1941  0
                                                         parentSets[iParentSet].SetParent(iParent, offset[nParent]);
 1942  
                                                 }
 1943  
                                         }
 1944  
                                 }
 1945  0
                                 m_ParentSets = parentSets;
 1946  
                                 // update distributions
 1947  0
                                 Estimator[][] distributions = new Estimator[nAtts][];
 1948  0
                                 iTargetNode = 0;
 1949  0
                                 for (int iNode = 0; iNode < nAtts; iNode++) {
 1950  0
                                         if (iTargetNode < m_nodes.size() && (Integer) m_nodes.elementAt(iTargetNode) == (Integer) iNode) {
 1951  0
                                                 SerializedObject so = new SerializedObject(m_CPT[iTargetNode]);
 1952  0
                                                 distributions[iNode] = (Estimator[]) so.getObject();
 1953  0
                                                 iTargetNode++;
 1954  0
                                         } else {
 1955  0
                                                 distributions[iNode] = m_Distributions[iNode - iTargetNode];
 1956  
                                         }
 1957  
                                 }
 1958  0
                                 m_Distributions = distributions;
 1959  
 
 1960  0
                                 for (int iNode = 0; iNode < m_nodes.size(); iNode++) {
 1961  0
                                         int nTargetNode = (Integer) m_nodes.elementAt(iNode);
 1962  0
                                         m_nPositionX.insertElementAt(m_nPosX[iNode], nTargetNode);
 1963  0
                                         m_nPositionY.insertElementAt(m_nPosY[iNode], nTargetNode);
 1964  0
                                         m_nEvidence.insertElementAt(-1, nTargetNode);
 1965  0
                                         m_fMarginP.insertElementAt(new double[getCardinality(nTargetNode)], nTargetNode);
 1966  
                                 }
 1967  0
                                 for (int deletedArc = 0; deletedArc < m_deleteArcActions.size(); deletedArc++) {
 1968  0
                                         DeleteArcAction action = (DeleteArcAction) m_deleteArcActions.elementAt(deletedArc);
 1969  0
                                         action.undo();
 1970  
                                 }
 1971  0
                         } catch (Exception e) {
 1972  0
                                 e.printStackTrace();
 1973  0
                         }
 1974  0
                 } // undo
 1975  
 
 1976  
                 public void redo() {
 1977  
                         try {
 1978  0
                                 for (int iNode = m_nodes.size() - 1; iNode >= 0; iNode--) {
 1979  0
                                         int nNode = (Integer) m_nodes.elementAt(iNode);
 1980  0
                                         deleteNode(nNode);
 1981  
                                 }
 1982  0
                         } catch (Exception e) {
 1983  0
                                 e.printStackTrace();
 1984  0
                         }
 1985  0
                 } // redo
 1986  
         } // class DeleteSelectionAction
 1987  
 
 1988  
         class AddArcAction extends UndoAction {
 1989  
                 /** for serialization */
 1990  
                 static final long serialVersionUID = 1;
 1991  
                 //int m_nChild;
 1992  
                 FastVector m_children;
 1993  
 
 1994  
                 int m_nParent;
 1995  
 
 1996  
                 Estimator[][] m_CPT;
 1997  
 
 1998  0
                 AddArcAction(int nParent, int nChild) {
 1999  
                         try {
 2000  0
                                 m_nParent = nParent;
 2001  0
                                 m_children = new FastVector();
 2002  0
                                 m_children.addElement(nChild);
 2003  
                                 //m_nChild = nChild;
 2004  0
                                 SerializedObject so = new SerializedObject(m_Distributions[nChild]);
 2005  0
                                 m_CPT = new Estimator[1][];
 2006  0
                                 m_CPT[0] = (Estimator[]) so.getObject();
 2007  
                                 ;
 2008  0
                         } catch (Exception e) {
 2009  0
                                 e.printStackTrace();
 2010  0
                         }
 2011  0
                 } // c'tor
 2012  
 
 2013  0
                 AddArcAction(int nParent, FastVector children) {
 2014  
                         try {
 2015  0
                                 m_nParent = nParent;
 2016  0
                                 m_children = new FastVector();
 2017  0
                                 m_CPT = new Estimator[children.size()][];
 2018  0
                                 for (int iChild = 0; iChild < children.size(); iChild++) {
 2019  0
                                         int nChild = (Integer) children.elementAt(iChild);
 2020  0
                                         m_children.addElement(nChild);
 2021  0
                                         SerializedObject so = new SerializedObject(m_Distributions[nChild]);
 2022  0
                                         m_CPT[iChild] = (Estimator[]) so.getObject();
 2023  
                                 }
 2024  0
                         } catch (Exception e) {
 2025  0
                                 e.printStackTrace();
 2026  0
                         }
 2027  0
                 } // c'tor
 2028  
 
 2029  
                 public void undo() {
 2030  
                         try {
 2031  0
                                 for (int iChild = 0; iChild < m_children.size(); iChild++) {
 2032  0
                                         int nChild = (Integer) m_children.elementAt(iChild);
 2033  0
                                         deleteArc(m_nParent, nChild);
 2034  0
                                         SerializedObject so = new SerializedObject(m_CPT[iChild]);
 2035  0
                                         m_Distributions[nChild] = (Estimator[]) so.getObject();
 2036  
                                 }
 2037  0
                         } catch (Exception e) {
 2038  0
                                 e.printStackTrace();
 2039  0
                         }
 2040  0
                 } // undo
 2041  
 
 2042  
                 public void redo() {
 2043  
                         try {
 2044  0
                                 for (int iChild = 0; iChild < m_children.size(); iChild++) {
 2045  0
                                         int nChild = (Integer) m_children.elementAt(iChild);
 2046  0
                                         addArc(m_nParent, nChild);
 2047  
                                 }
 2048  0
                         } catch (Exception e) {
 2049  0
                                 e.printStackTrace();
 2050  0
                         }
 2051  0
                 } // redo
 2052  
         } // class AddArcAction
 2053  
 
 2054  
         class DeleteArcAction extends UndoAction {
 2055  
                 /** for serialization */
 2056  
                 static final long serialVersionUID = 1;
 2057  
                 int[] m_nParents;
 2058  
                 int m_nChild;
 2059  
                 int m_nParent;
 2060  
                 Estimator[] m_CPT;
 2061  
 
 2062  0
                 DeleteArcAction(int nParent, int nChild) {
 2063  
                         try {
 2064  0
                         m_nChild = nChild;
 2065  0
                         m_nParent = nParent;
 2066  0
                         m_nParents = new int[getNrOfParents(nChild)];
 2067  0
                         for (int iParent = 0; iParent < m_nParents.length; iParent++) {
 2068  0
                                 m_nParents[iParent] = getParent(nChild, iParent);
 2069  
                         }
 2070  0
                         SerializedObject so = new SerializedObject(m_Distributions[nChild]);
 2071  0
                         m_CPT = (Estimator[]) so.getObject();
 2072  0
                         } catch (Exception e) {
 2073  0
                                 e.printStackTrace();
 2074  0
                         }
 2075  0
                 } // c'tor
 2076  
 
 2077  
                 public void undo() {
 2078  
                         try {
 2079  0
                                 SerializedObject so = new SerializedObject(m_CPT);
 2080  0
                                 m_Distributions[m_nChild] = (Estimator[]) so.getObject();
 2081  0
                                 ParentSet parentSet = new ParentSet();
 2082  0
                                 for (int iParent = 0; iParent < m_nParents.length; iParent++) {
 2083  0
                                         parentSet.addParent(m_nParents[iParent], m_Instances);
 2084  
                                 }
 2085  0
                                 m_ParentSets[m_nChild] = parentSet;
 2086  0
                         } catch (Exception e) {
 2087  0
                                 e.printStackTrace();
 2088  0
                         }
 2089  0
                 } // undo
 2090  
 
 2091  
                 public void redo() {
 2092  
                         try {
 2093  0
                                 deleteArc(m_nParent, m_nChild);
 2094  0
                         } catch (Exception e) {
 2095  0
                                 e.printStackTrace();
 2096  0
                         }
 2097  0
                 } // redo
 2098  
         } // class DeleteArcAction
 2099  
 
 2100  
         class SetDistributionAction extends UndoAction {
 2101  
                 /** for serialization */
 2102  
                 static final long serialVersionUID = 1;
 2103  
                 int m_nTargetNode;
 2104  
 
 2105  
                 Estimator[] m_CPT;
 2106  
 
 2107  
                 double[][] m_P;
 2108  
 
 2109  0
                 SetDistributionAction(int nTargetNode, double[][] P) {
 2110  
                         try {
 2111  0
                                 m_nTargetNode = nTargetNode;
 2112  0
                                 SerializedObject so = new SerializedObject(m_Distributions[nTargetNode]);
 2113  0
                                 m_CPT = (Estimator[]) so.getObject();
 2114  
                                 ;
 2115  0
                                 m_P = P;
 2116  0
                         } catch (Exception e) {
 2117  0
                                 e.printStackTrace();
 2118  0
                         }
 2119  0
                 } // c'tor
 2120  
 
 2121  
                 public void undo() {
 2122  
                         try {
 2123  0
                                 SerializedObject so = new SerializedObject(m_CPT);
 2124  0
                                 m_Distributions[m_nTargetNode] = (Estimator[]) so.getObject();
 2125  0
                         } catch (Exception e) {
 2126  0
                                 e.printStackTrace();
 2127  0
                         }
 2128  0
                 } // undo
 2129  
 
 2130  
                 public void redo() {
 2131  
                         try {
 2132  0
                                 setDistribution(m_nTargetNode, m_P);
 2133  0
                         } catch (Exception e) {
 2134  0
                                 e.printStackTrace();
 2135  0
                         }
 2136  0
                 } // redo
 2137  
 
 2138  
                 public String getUndoMsg() {
 2139  0
                         return "Distribution of node " + getNodeName(m_nTargetNode) + " changed";
 2140  
                 }
 2141  
 
 2142  
                 public String getRedoMsg() {
 2143  0
                         return "Distribution of node " + getNodeName(m_nTargetNode) + " changed";
 2144  
                 }
 2145  
         } // class SetDistributionAction
 2146  
 
 2147  
         class RenameAction extends UndoAction {
 2148  
                 /** for serialization */
 2149  
                 static final long serialVersionUID = 1;
 2150  
                 int m_nTargetNode;
 2151  
 
 2152  
                 String m_sNewName;
 2153  
 
 2154  
                 String m_sOldName;
 2155  
 
 2156  0
                 RenameAction(int nTargetNode, String sOldName, String sNewName) {
 2157  0
                         m_nTargetNode = nTargetNode;
 2158  0
                         m_sNewName = sNewName;
 2159  0
                         m_sOldName = sOldName;
 2160  0
                 } // c'tor
 2161  
 
 2162  
                 public void undo() {
 2163  0
                         setNodeName(m_nTargetNode, m_sOldName);
 2164  0
                 } // undo
 2165  
 
 2166  
                 public void redo() {
 2167  0
                         setNodeName(m_nTargetNode, m_sNewName);
 2168  0
                 } // redo
 2169  
         } // class RenameAction
 2170  
 
 2171  
         class RenameValueAction extends RenameAction {
 2172  
                 /** for serialization */
 2173  
                 static final long serialVersionUID = 1;
 2174  0
                 RenameValueAction(int nTargetNode, String sOldName, String sNewName) {
 2175  0
                         super(nTargetNode, sOldName, sNewName);
 2176  0
                 } // c'tor
 2177  
 
 2178  
                 public void undo() {
 2179  0
                         renameNodeValue(m_nTargetNode, m_sNewName, m_sOldName);
 2180  0
                 } // undo
 2181  
 
 2182  
                 public void redo() {
 2183  0
                         renameNodeValue(m_nTargetNode, m_sOldName, m_sNewName);
 2184  0
                 } // redo
 2185  
 
 2186  
                 public String getUndoMsg() {
 2187  0
                         return "Value of node " + getNodeName(m_nTargetNode) + " changed from " + m_sNewName + " to " + m_sOldName;
 2188  
                 }
 2189  
 
 2190  
                 public String getRedoMsg() {
 2191  0
                         return "Value of node " + getNodeName(m_nTargetNode) + " changed from " + m_sOldName + " to " + m_sNewName;
 2192  
                 }
 2193  
         } // class RenameValueAction
 2194  
 
 2195  
         class AddValueAction extends UndoAction {
 2196  
                 /** for serialization */
 2197  
                 static final long serialVersionUID = 1;
 2198  
                 int m_nTargetNode;
 2199  
 
 2200  
                 String m_sValue;
 2201  
 
 2202  0
                 AddValueAction(int nTargetNode, String sValue) {
 2203  0
                         m_nTargetNode = nTargetNode;
 2204  0
                         m_sValue = sValue;
 2205  0
                 } // c'tor
 2206  
 
 2207  
                 public void undo() {
 2208  
                         try {
 2209  0
                                 delNodeValue(m_nTargetNode, m_sValue);
 2210  0
                         } catch (Exception e) {
 2211  0
                                 e.printStackTrace();
 2212  0
                         }
 2213  0
                 } // undo
 2214  
 
 2215  
                 public void redo() {
 2216  0
                         addNodeValue(m_nTargetNode, m_sValue);
 2217  0
                 } // redo
 2218  
 
 2219  
                 public String getUndoMsg() {
 2220  0
                         return "Value " + m_sValue + " removed from node " + getNodeName(m_nTargetNode);
 2221  
                 }
 2222  
 
 2223  
                 public String getRedoMsg() {
 2224  0
                         return "Value " + m_sValue + " added to node " + getNodeName(m_nTargetNode);
 2225  
                 }
 2226  
         } // class AddValueAction
 2227  
 
 2228  
         class DelValueAction extends UndoAction {
 2229  
                 /** for serialization */
 2230  
                 static final long serialVersionUID = 1;
 2231  
                 int m_nTargetNode;
 2232  
 
 2233  
                 String m_sValue;
 2234  
 
 2235  
                 Estimator[] m_CPT;
 2236  
 
 2237  
                 FastVector m_children;
 2238  
 
 2239  
                 Estimator[][] m_childAtts;
 2240  
 
 2241  
                 Attribute m_att;
 2242  
 
 2243  0
                 DelValueAction(int nTargetNode, String sValue) {
 2244  
                         try {
 2245  0
                                 m_nTargetNode = nTargetNode;
 2246  0
                                 m_sValue = sValue;
 2247  0
                                 m_att = m_Instances.attribute(nTargetNode);
 2248  0
                                 SerializedObject so = new SerializedObject(m_Distributions[nTargetNode]);
 2249  0
                                 m_CPT = (Estimator[]) so.getObject();
 2250  
                                 ;
 2251  0
                                 m_children = new FastVector();
 2252  0
                                 for (int iNode = 0; iNode < getNrOfNodes(); iNode++) {
 2253  0
                                         if (m_ParentSets[iNode].contains(nTargetNode)) {
 2254  0
                                                 m_children.addElement(iNode);
 2255  
                                         }
 2256  
                                 }
 2257  0
                                 m_childAtts = new Estimator[m_children.size()][];
 2258  0
                                 for (int iChild = 0; iChild < m_children.size(); iChild++) {
 2259  0
                                         int nChild = (Integer) m_children.elementAt(iChild);
 2260  0
                                         m_childAtts[iChild] = m_Distributions[nChild];
 2261  
                                 }
 2262  0
                         } catch (Exception e) {
 2263  0
                                 e.printStackTrace();
 2264  0
                         }
 2265  0
                 } // c'tor
 2266  
 
 2267  
                 public void undo() {
 2268  
                         try {
 2269  0
                                 m_Instances.insertAttributeAt(m_att, m_nTargetNode);
 2270  0
                                 SerializedObject so = new SerializedObject(m_CPT);
 2271  0
                                 m_Distributions[m_nTargetNode] = (Estimator[]) so.getObject();
 2272  0
                                 for (int iChild = 0; iChild < m_children.size(); iChild++) {
 2273  0
                                         int nChild = (Integer) m_children.elementAt(iChild);
 2274  0
                                         m_Instances.insertAttributeAt(m_att, m_nTargetNode);
 2275  0
                                         so = new SerializedObject(m_childAtts[iChild]);
 2276  0
                                         m_Distributions[nChild] = (Estimator[]) so.getObject();
 2277  
                                 }
 2278  0
                         } catch (Exception e) {
 2279  0
                                 e.printStackTrace();
 2280  0
                         }
 2281  0
                 } // undo
 2282  
 
 2283  
                 public void redo() {
 2284  
                         try {
 2285  0
                                 delNodeValue(m_nTargetNode, m_sValue);
 2286  0
                         } catch (Exception e) {
 2287  0
                                 e.printStackTrace();
 2288  0
                         }
 2289  0
                 } // redo
 2290  
 
 2291  
                 public String getUndoMsg() {
 2292  0
                         return "Value " + m_sValue + " added to node " + getNodeName(m_nTargetNode);
 2293  
                 }
 2294  
 
 2295  
                 public String getRedoMsg() {
 2296  0
                         return "Value " + m_sValue + " removed from node " + getNodeName(m_nTargetNode);
 2297  
                 }
 2298  
         } // class DelValueAction
 2299  
 
 2300  
         class alignAction extends UndoAction {
 2301  
                 /** for serialization */
 2302  
                 static final long serialVersionUID = 1;
 2303  
                 FastVector m_nodes;
 2304  
 
 2305  
                 FastVector m_posX;
 2306  
 
 2307  
                 FastVector m_posY;
 2308  
 
 2309  0
                 alignAction(FastVector nodes) {
 2310  0
                         m_nodes = new FastVector(nodes.size());
 2311  0
                         m_posX = new FastVector(nodes.size());
 2312  0
                         m_posY = new FastVector(nodes.size());
 2313  0
                         for (int iNode = 0; iNode < nodes.size(); iNode++) {
 2314  0
                                 int nNode = (Integer) nodes.elementAt(iNode);
 2315  0
                                 m_nodes.addElement(nNode);
 2316  0
                                 m_posX.addElement(getPositionX(nNode));
 2317  0
                                 m_posY.addElement(getPositionY(nNode));
 2318  
                         }
 2319  0
                 } // c'tor
 2320  
 
 2321  
                 public void undo() {
 2322  
                         try {
 2323  0
                                 for (int iNode = 0; iNode < m_nodes.size(); iNode++) {
 2324  0
                                         int nNode = (Integer) m_nodes.elementAt(iNode);
 2325  0
                                         setPosition(nNode, (Integer) m_posX.elementAt(iNode), (Integer) m_posY.elementAt(iNode));
 2326  
                                 }
 2327  0
                         } catch (Exception e) {
 2328  0
                                 e.printStackTrace();
 2329  0
                         }
 2330  0
                 } // undo
 2331  
         } // class alignAction
 2332  
 
 2333  
         class alignLeftAction extends alignAction {
 2334  
                 /** for serialization */
 2335  
                 static final long serialVersionUID = 1;
 2336  0
                 public alignLeftAction(FastVector nodes) {
 2337  0
                         super(nodes);
 2338  0
                 } // c'tor
 2339  
 
 2340  
                 public void redo() {
 2341  
                         try {
 2342  0
                                 alignLeft(m_nodes);
 2343  0
                         } catch (Exception e) {
 2344  0
                                 e.printStackTrace();
 2345  0
                         }
 2346  0
                 } // redo
 2347  
 
 2348  
                 public String getUndoMsg() {
 2349  0
                         return "Returning " + m_nodes.size() + " from aliging nodes to the left.";
 2350  
                 }
 2351  
 
 2352  
                 public String getRedoMsg() {
 2353  0
                         return "Aligning " + m_nodes.size() + " nodes to the left.";
 2354  
                 }
 2355  
         } // class alignLeftAction
 2356  
 
 2357  
         class alignRightAction extends alignAction {
 2358  
                 /** for serialization */
 2359  
                 static final long serialVersionUID = 1;
 2360  0
                 public alignRightAction(FastVector nodes) {
 2361  0
                         super(nodes);
 2362  0
                 } // c'tor
 2363  
 
 2364  
                 public void redo() {
 2365  
                         try {
 2366  0
                                 alignRight(m_nodes);
 2367  0
                         } catch (Exception e) {
 2368  0
                                 e.printStackTrace();
 2369  0
                         }
 2370  0
                 } // redo
 2371  
 
 2372  
                 public String getUndoMsg() {
 2373  0
                         return "Returning " + m_nodes.size() + " from aliging nodes to the right.";
 2374  
                 }
 2375  
 
 2376  
                 public String getRedoMsg() {
 2377  0
                         return "Aligning " + m_nodes.size() + " nodes to the right.";
 2378  
                 }
 2379  
         } // class alignLeftAction
 2380  
 
 2381  
         class alignTopAction extends alignAction {
 2382  
                 /** for serialization */
 2383  
                 static final long serialVersionUID = 1;
 2384  0
                 public alignTopAction(FastVector nodes) {
 2385  0
                         super(nodes);
 2386  0
                 } // c'tor
 2387  
 
 2388  
                 public void redo() {
 2389  
                         try {
 2390  0
                                 alignTop(m_nodes);
 2391  0
                         } catch (Exception e) {
 2392  0
                                 e.printStackTrace();
 2393  0
                         }
 2394  0
                 } // redo
 2395  
 
 2396  
                 public String getUndoMsg() {
 2397  0
                         return "Returning " + m_nodes.size() + " from aliging nodes to the top.";
 2398  
                 }
 2399  
 
 2400  
                 public String getRedoMsg() {
 2401  0
                         return "Aligning " + m_nodes.size() + " nodes to the top.";
 2402  
                 }
 2403  
         } // class alignTopAction
 2404  
 
 2405  
         class alignBottomAction extends alignAction {
 2406  
                 /** for serialization */
 2407  
                 static final long serialVersionUID = 1;
 2408  0
                 public alignBottomAction(FastVector nodes) {
 2409  0
                         super(nodes);
 2410  0
                 } // c'tor
 2411  
 
 2412  
                 public void redo() {
 2413  
                         try {
 2414  0
                                 alignBottom(m_nodes);
 2415  0
                         } catch (Exception e) {
 2416  0
                                 e.printStackTrace();
 2417  0
                         }
 2418  0
                 } // redo
 2419  
 
 2420  
                 public String getUndoMsg() {
 2421  0
                         return "Returning " + m_nodes.size() + " from aliging nodes to the bottom.";
 2422  
                 }
 2423  
 
 2424  
                 public String getRedoMsg() {
 2425  0
                         return "Aligning " + m_nodes.size() + " nodes to the bottom.";
 2426  
                 }
 2427  
         } // class alignBottomAction
 2428  
 
 2429  
         class centerHorizontalAction extends alignAction {
 2430  
                 /** for serialization */
 2431  
                 static final long serialVersionUID = 1;
 2432  0
                 public centerHorizontalAction(FastVector nodes) {
 2433  0
                         super(nodes);
 2434  0
                 } // c'tor
 2435  
 
 2436  
                 public void redo() {
 2437  
                         try {
 2438  0
                                 centerHorizontal(m_nodes);
 2439  0
                         } catch (Exception e) {
 2440  0
                                 e.printStackTrace();
 2441  0
                         }
 2442  0
                 } // redo
 2443  
 
 2444  
                 public String getUndoMsg() {
 2445  0
                         return "Returning " + m_nodes.size() + " from centering horizontally.";
 2446  
                 }
 2447  
 
 2448  
                 public String getRedoMsg() {
 2449  0
                         return "Centering " + m_nodes.size() + " nodes horizontally.";
 2450  
                 }
 2451  
         } // class centerHorizontalAction
 2452  
 
 2453  
         class centerVerticalAction extends alignAction {
 2454  
                 /** for serialization */
 2455  
                 static final long serialVersionUID = 1;
 2456  0
                 public centerVerticalAction(FastVector nodes) {
 2457  0
                         super(nodes);
 2458  0
                 } // c'tor
 2459  
 
 2460  
                 public void redo() {
 2461  
                         try {
 2462  0
                                 centerVertical(m_nodes);
 2463  0
                         } catch (Exception e) {
 2464  0
                                 e.printStackTrace();
 2465  0
                         }
 2466  0
                 } // redo
 2467  
 
 2468  
                 public String getUndoMsg() {
 2469  0
                         return "Returning " + m_nodes.size() + " from centering vertically.";
 2470  
                 }
 2471  
 
 2472  
                 public String getRedoMsg() {
 2473  0
                         return "Centering " + m_nodes.size() + " nodes vertically.";
 2474  
                 }
 2475  
         } // class centerVerticalAction
 2476  
 
 2477  
         class spaceHorizontalAction extends alignAction {
 2478  
                 /** for serialization */
 2479  
                 static final long serialVersionUID = 1;
 2480  0
                 public spaceHorizontalAction(FastVector nodes) {
 2481  0
                         super(nodes);
 2482  0
                 } // c'tor
 2483  
 
 2484  
                 public void redo() {
 2485  
                         try {
 2486  0
                                 spaceHorizontal(m_nodes);
 2487  0
                         } catch (Exception e) {
 2488  0
                                 e.printStackTrace();
 2489  0
                         }
 2490  0
                 } // redo
 2491  
 
 2492  
                 public String getUndoMsg() {
 2493  0
                         return "Returning " + m_nodes.size() + " from spaceing horizontally.";
 2494  
                 }
 2495  
 
 2496  
                 public String getRedoMsg() {
 2497  0
                         return "spaceing " + m_nodes.size() + " nodes horizontally.";
 2498  
                 }
 2499  
         } // class spaceHorizontalAction
 2500  
 
 2501  
         class spaceVerticalAction extends alignAction {
 2502  
                 /** for serialization */
 2503  
                 static final long serialVersionUID = 1;
 2504  0
                 public spaceVerticalAction(FastVector nodes) {
 2505  0
                         super(nodes);
 2506  0
                 } // c'tor
 2507  
 
 2508  
                 public void redo() {
 2509  
                         try {
 2510  0
                                 spaceVertical(m_nodes);
 2511  0
                         } catch (Exception e) {
 2512  0
                                 e.printStackTrace();
 2513  0
                         }
 2514  0
                 } // redo
 2515  
 
 2516  
                 public String getUndoMsg() {
 2517  0
                         return "Returning " + m_nodes.size() + " from spaceng vertically.";
 2518  
                 }
 2519  
 
 2520  
                 public String getRedoMsg() {
 2521  0
                         return "Spaceng " + m_nodes.size() + " nodes vertically.";
 2522  
                 }
 2523  
         } // class spaceVerticalAction
 2524  
 
 2525  
         class SetPositionAction extends UndoAction {
 2526  
                 /** for serialization */
 2527  
                 static final long serialVersionUID = 1;
 2528  
                 int m_nTargetNode;
 2529  
 
 2530  
                 int m_nX;
 2531  
 
 2532  
                 int m_nY;
 2533  
 
 2534  
                 int m_nX2;
 2535  
 
 2536  
                 int m_nY2;
 2537  
 
 2538  0
                 SetPositionAction(int nTargetNode, int nX, int nY) {
 2539  0
                         m_nTargetNode = nTargetNode;
 2540  0
                         m_nX2 = nX;
 2541  0
                         m_nY2 = nY;
 2542  0
                         m_nX = getPositionX(nTargetNode);
 2543  0
                         m_nY = getPositionY(nTargetNode);
 2544  0
                 } // c'tor
 2545  
 
 2546  
                 public void undo() {
 2547  0
                         setPosition(m_nTargetNode, m_nX, m_nY);
 2548  0
                 } // undo
 2549  
 
 2550  
                 public void redo() {
 2551  0
                         setPosition(m_nTargetNode, m_nX2, m_nY2);
 2552  0
                 } // redo
 2553  
 
 2554  
                 public void setUndoPosition(int nX, int nY) {
 2555  0
                         m_nX2 = nX;
 2556  0
                         m_nY2 = nY;
 2557  0
                 } // setPosition
 2558  
         } // class SetPositionAction
 2559  
 
 2560  
         class SetGroupPositionAction extends UndoAction {
 2561  
                 /** for serialization */
 2562  
                 static final long serialVersionUID = 1;
 2563  
                 FastVector m_nodes;
 2564  
                 int m_dX;
 2565  
                 int m_dY;
 2566  
 
 2567  0
                 SetGroupPositionAction(FastVector nodes, int dX, int dY) {
 2568  0
                         m_nodes = new FastVector(nodes.size());
 2569  0
                         for (int iNode = 0; iNode < nodes.size(); iNode++) {
 2570  0
                                 m_nodes.addElement(nodes.elementAt(iNode));
 2571  
                         }
 2572  0
                         m_dX = dX;
 2573  0
                         m_dY = dY;
 2574  0
                 } // c'tor
 2575  
 
 2576  
                 public void undo() {
 2577  0
                         for (int iNode = 0; iNode < m_nodes.size(); iNode++) {
 2578  0
                                 int nNode = (Integer) m_nodes.elementAt(iNode);
 2579  0
                                 setPosition(nNode, getPositionX(nNode) - m_dX,  getPositionY(nNode) - m_dY);
 2580  
                         }
 2581  0
                 } // undo
 2582  
 
 2583  
                 public void redo() {
 2584  0
                         for (int iNode = 0; iNode < m_nodes.size(); iNode++) {
 2585  0
                                 int nNode = (Integer) m_nodes.elementAt(iNode);
 2586  0
                                 setPosition(nNode, getPositionX(nNode) + m_dX,  getPositionY(nNode) + m_dY);
 2587  
                         }
 2588  0
                 } // redo
 2589  
                 public void setUndoPosition(int dX, int dY) {
 2590  0
                         m_dX += dX;
 2591  0
                         m_dY += dY;
 2592  0
                 } // setPosition
 2593  
         } // class SetGroupPositionAction
 2594  
 
 2595  
         class LayoutGraphAction extends UndoAction {
 2596  
                 /** for serialization */
 2597  
                 static final long serialVersionUID = 1;
 2598  
                 FastVector m_nPosX;
 2599  
                 FastVector m_nPosY;
 2600  
                 FastVector m_nPosX2;
 2601  
                 FastVector m_nPosY2;
 2602  
 
 2603  0
                 LayoutGraphAction(FastVector nPosX, FastVector nPosY) {
 2604  0
                         m_nPosX = new FastVector(nPosX.size());
 2605  0
                         m_nPosY = new FastVector(nPosX.size());
 2606  0
                         m_nPosX2 = new FastVector(nPosX.size());
 2607  0
                         m_nPosY2 = new FastVector(nPosX.size());
 2608  0
                         for (int iNode = 0; iNode < nPosX.size(); iNode++) {
 2609  0
                                 m_nPosX.addElement(m_nPositionX.elementAt(iNode));
 2610  0
                                 m_nPosY.addElement(m_nPositionY.elementAt(iNode));
 2611  0
                                 m_nPosX2.addElement(nPosX.elementAt(iNode));
 2612  0
                                 m_nPosY2.addElement(nPosY.elementAt(iNode));
 2613  
                         }
 2614  0
                 } // c'tor
 2615  
 
 2616  
                 public void undo() {
 2617  0
                         for (int iNode = 0; iNode < m_nPosX.size(); iNode++) {
 2618  0
                                 setPosition(iNode, (Integer) m_nPosX.elementAt(iNode), (Integer) m_nPosY.elementAt(iNode));
 2619  
                         }
 2620  0
                 } // undo
 2621  
 
 2622  
                 public void redo() {
 2623  0
                         for (int iNode = 0; iNode < m_nPosX.size(); iNode++) {
 2624  0
                                 setPosition(iNode, (Integer) m_nPosX2.elementAt(iNode), (Integer) m_nPosY2.elementAt(iNode));
 2625  
                         }
 2626  0
                 } // redo
 2627  
         } // class LayoutGraphAction
 2628  
 
 2629  
         class PasteAction extends UndoAction {
 2630  
                 /** for serialization */
 2631  
                 static final long serialVersionUID = 1;
 2632  
                 int m_nBase;
 2633  
 
 2634  
                 String m_sXML;
 2635  
 
 2636  0
                 PasteAction(String sXML, int nBase) {
 2637  0
                         m_sXML = sXML;
 2638  0
                         m_nBase = nBase;
 2639  0
                 } // c'tor
 2640  
 
 2641  
                 public void undo() {
 2642  
                         try {
 2643  0
                                 int iNode = getNrOfNodes() - 1;
 2644  0
                                 while (iNode >= m_nBase) {
 2645  0
                                         deleteNode(iNode);
 2646  0
                                         iNode--;
 2647  
                                 }
 2648  0
                         } catch (Exception e) {
 2649  0
                                 e.printStackTrace();
 2650  0
                         }
 2651  0
                 } // undo
 2652  
 
 2653  
                 public void redo() {
 2654  
                         try {
 2655  0
                                 paste(m_sXML, EXECUTE);
 2656  0
                         } catch (Exception e) {
 2657  0
                                 e.printStackTrace();
 2658  0
                         }
 2659  0
                 } // redo
 2660  
         } // class PasteAction
 2661  
           
 2662  
           /**
 2663  
            * Returns the revision string.
 2664  
            * 
 2665  
            * @return                the revision
 2666  
            */
 2667  
           public String getRevision() {
 2668  0
             return RevisionUtils.extract("$Revision: 8034 $");
 2669  
           }
 2670  
 
 2671  
         /**
 2672  
          * @param args
 2673  
          */
 2674  
         public static void main(String[] args) {
 2675  0
         } // main
 2676  
 } // class EditableBayesNet
 2677