Coverage Report - weka.classifiers.bayes.net.search.local.TabuSearch
 
Classes in this File Line Coverage Branch Coverage Complexity
TabuSearch
0%
0/93
0%
0/32
2.125
 
 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  
  * TabuSearch.java
 18  
  * Copyright (C) 2004-2012 University of Waikato, Hamilton, New Zealand
 19  
  * 
 20  
  */
 21  
  
 22  
 package weka.classifiers.bayes.net.search.local;
 23  
 
 24  
 import java.util.Enumeration;
 25  
 import java.util.Vector;
 26  
 
 27  
 import weka.classifiers.bayes.BayesNet;
 28  
 import weka.core.Instances;
 29  
 import weka.core.Option;
 30  
 import weka.core.RevisionUtils;
 31  
 import weka.core.TechnicalInformation;
 32  
 import weka.core.TechnicalInformation.Field;
 33  
 import weka.core.TechnicalInformation.Type;
 34  
 import weka.core.TechnicalInformationHandler;
 35  
 import weka.core.Utils;
 36  
 
 37  
 /** 
 38  
  <!-- globalinfo-start -->
 39  
  * This Bayes Network learning algorithm uses tabu search for finding a well scoring Bayes network structure. Tabu search is hill climbing till an optimum is reached. The following step is the least worst possible step. The last X steps are kept in a list and none of the steps in this so called tabu list is considered in taking the next step. The best network found in this traversal is returned.<br/>
 40  
  * <br/>
 41  
  * For more information see:<br/>
 42  
  * <br/>
 43  
  * R.R. Bouckaert (1995). Bayesian Belief Networks: from Construction to Inference. Utrecht, Netherlands.
 44  
  * <p/>
 45  
  <!-- globalinfo-end -->
 46  
  * 
 47  
  <!-- technical-bibtex-start -->
 48  
  * BibTeX:
 49  
  * <pre>
 50  
  * &#64;phdthesis{Bouckaert1995,
 51  
  *    address = {Utrecht, Netherlands},
 52  
  *    author = {R.R. Bouckaert},
 53  
  *    institution = {University of Utrecht},
 54  
  *    title = {Bayesian Belief Networks: from Construction to Inference},
 55  
  *    year = {1995}
 56  
  * }
 57  
  * </pre>
 58  
  * <p/>
 59  
  <!-- technical-bibtex-end -->
 60  
  * 
 61  
  <!-- options-start -->
 62  
  * Valid options are: <p/>
 63  
  * 
 64  
  * <pre> -L &lt;integer&gt;
 65  
  *  Tabu list length</pre>
 66  
  * 
 67  
  * <pre> -U &lt;integer&gt;
 68  
  *  Number of runs</pre>
 69  
  * 
 70  
  * <pre> -P &lt;nr of parents&gt;
 71  
  *  Maximum number of parents</pre>
 72  
  * 
 73  
  * <pre> -R
 74  
  *  Use arc reversal operation.
 75  
  *  (default false)</pre>
 76  
  * 
 77  
  * <pre> -P &lt;nr of parents&gt;
 78  
  *  Maximum number of parents</pre>
 79  
  * 
 80  
  * <pre> -R
 81  
  *  Use arc reversal operation.
 82  
  *  (default false)</pre>
 83  
  * 
 84  
  * <pre> -N
 85  
  *  Initial structure is empty (instead of Naive Bayes)</pre>
 86  
  * 
 87  
  * <pre> -mbc
 88  
  *  Applies a Markov Blanket correction to the network structure, 
 89  
  *  after a network structure is learned. This ensures that all 
 90  
  *  nodes in the network are part of the Markov blanket of the 
 91  
  *  classifier node.</pre>
 92  
  * 
 93  
  * <pre> -S [BAYES|MDL|ENTROPY|AIC|CROSS_CLASSIC|CROSS_BAYES]
 94  
  *  Score type (BAYES, BDeu, MDL, ENTROPY and AIC)</pre>
 95  
  * 
 96  
  <!-- options-end -->
 97  
  * 
 98  
  * @author Remco Bouckaert (rrb@xm.co.nz)
 99  
  * @version $Revision: 8034 $
 100  
  */
 101  0
 public class TabuSearch 
 102  
     extends HillClimber
 103  
     implements TechnicalInformationHandler {
 104  
   
 105  
     /** for serialization */
 106  
     static final long serialVersionUID = 1457344073228786447L;
 107  
 
 108  
     /** number of runs **/
 109  0
     int m_nRuns = 10;
 110  
                     
 111  
         /** size of tabu list **/
 112  0
         int m_nTabuList = 5;
 113  
 
 114  
         /** the actual tabu list **/
 115  0
         Operation[] m_oTabuList = null;
 116  
 
 117  
         /**
 118  
          * Returns an instance of a TechnicalInformation object, containing 
 119  
          * detailed information about the technical background of this class,
 120  
          * e.g., paper reference or book this class is based on.
 121  
          * 
 122  
          * @return the technical information about this class
 123  
          */
 124  
         public TechnicalInformation getTechnicalInformation() {
 125  
           TechnicalInformation         result;
 126  
           
 127  0
           result = new TechnicalInformation(Type.PHDTHESIS);
 128  0
           result.setValue(Field.AUTHOR, "R.R. Bouckaert");
 129  0
           result.setValue(Field.YEAR, "1995");
 130  0
           result.setValue(Field.TITLE, "Bayesian Belief Networks: from Construction to Inference");
 131  0
           result.setValue(Field.INSTITUTION, "University of Utrecht");
 132  0
           result.setValue(Field.ADDRESS, "Utrecht, Netherlands");
 133  
           
 134  0
           return result;
 135  
         }
 136  
 
 137  
         /**
 138  
           * search determines the network structure/graph of the network
 139  
           * with the Tabu search algorithm.
 140  
           * 
 141  
           * @param bayesNet the network
 142  
           * @param instances the data to use
 143  
           * @throws Exception if something goes wrong
 144  
          */
 145  
         protected void search(BayesNet bayesNet, Instances instances) throws Exception {
 146  0
         m_oTabuList = new Operation[m_nTabuList];
 147  0
         int iCurrentTabuList = 0;
 148  0
         initCache(bayesNet, instances);
 149  
 
 150  
                 // keeps track of score pf best structure found so far 
 151  
                 double fBestScore;        
 152  0
                 double fCurrentScore = 0.0;
 153  0
                 for (int iAttribute = 0; iAttribute < instances.numAttributes(); iAttribute++) {
 154  0
                         fCurrentScore += calcNodeScore(iAttribute);
 155  
                 }
 156  
 
 157  
                 // keeps track of best structure found so far 
 158  
                 BayesNet bestBayesNet;
 159  
 
 160  
                 // initialize bestBayesNet
 161  0
                 fBestScore = fCurrentScore;
 162  0
                 bestBayesNet = new BayesNet();
 163  0
                 bestBayesNet.m_Instances = instances;
 164  0
                 bestBayesNet.initStructure();
 165  0
                 copyParentSets(bestBayesNet, bayesNet);
 166  
                 
 167  
                 
 168  
         // go do the search        
 169  0
         for (int iRun = 0; iRun < m_nRuns; iRun++) {
 170  0
             Operation oOperation = getOptimalOperation(bayesNet, instances);
 171  0
                         performOperation(bayesNet, instances, oOperation);
 172  
             // sanity check
 173  0
             if (oOperation  == null) {
 174  0
                                 throw new Exception("Panic: could not find any step to make. Tabu list too long?");
 175  
             }
 176  
             // update tabu list
 177  0
             m_oTabuList[iCurrentTabuList] = oOperation;
 178  0
             iCurrentTabuList = (iCurrentTabuList + 1) % m_nTabuList;
 179  
 
 180  0
                         fCurrentScore += oOperation.m_fDeltaScore;
 181  
                         // keep track of best network seen so far
 182  0
                         if (fCurrentScore > fBestScore) {
 183  0
                                 fBestScore = fCurrentScore;
 184  0
                                 copyParentSets(bestBayesNet, bayesNet);
 185  
                         }
 186  
 
 187  0
                         if (bayesNet.getDebug()) {
 188  0
                                 printTabuList();
 189  
                         }
 190  
         }
 191  
         
 192  
         // restore current network to best network
 193  0
                 copyParentSets(bayesNet, bestBayesNet);
 194  
                 
 195  
                 // free up memory
 196  0
                 bestBayesNet = null;
 197  0
                 m_Cache = null;
 198  0
     } // search
 199  
 
 200  
 
 201  
         /** 
 202  
          * copyParentSets copies parent sets of source to dest BayesNet
 203  
          * 
 204  
          * @param dest destination network
 205  
          * @param source source network
 206  
          */
 207  
         void copyParentSets(BayesNet dest, BayesNet source) {
 208  0
                 int nNodes = source.getNrOfNodes();
 209  
                 // clear parent set first
 210  0
                 for (int iNode = 0; iNode < nNodes; iNode++) {
 211  0
                         dest.getParentSet(iNode).copy(source.getParentSet(iNode));
 212  
                 }                
 213  0
         } // CopyParentSets
 214  
 
 215  
         /** 
 216  
          * check whether the operation is not in the tabu list
 217  
          * 
 218  
          * @param oOperation operation to be checked
 219  
          * @return true if operation is not in the tabu list
 220  
          */
 221  
         boolean isNotTabu(Operation oOperation) {
 222  0
                 for (int iTabu = 0; iTabu < m_nTabuList; iTabu++) {
 223  0
                         if (oOperation.equals(m_oTabuList[iTabu])) {
 224  0
                                         return false;
 225  
                                 }
 226  
                 }
 227  0
                 return true;
 228  
         } // isNotTabu
 229  
 
 230  
         /** print tabu list for debugging purposes.
 231  
          */
 232  
         void printTabuList() {
 233  0
                 for (int i = 0; i < m_nTabuList; i++) {
 234  0
                         Operation o = m_oTabuList[i];
 235  0
                         if (o != null) {
 236  0
                                 if (o.m_nOperation == 0) {System.out.print(" +(");} else {System.out.print(" -(");}
 237  0
                                 System.out.print(o.m_nTail + "->" + o.m_nHead + ")");
 238  
                         }
 239  
                 }
 240  0
                 System.out.println();
 241  0
         } // printTabuList
 242  
 
 243  
     /**
 244  
     * @return number of runs
 245  
     */
 246  
     public int getRuns() {
 247  0
         return m_nRuns;
 248  
     } // getRuns
 249  
 
 250  
     /**
 251  
      * Sets the number of runs
 252  
      * @param nRuns The number of runs to set
 253  
      */
 254  
     public void setRuns(int nRuns) {
 255  0
         m_nRuns = nRuns;
 256  0
     } // setRuns
 257  
 
 258  
     /**
 259  
      * @return the Tabu List length
 260  
      */
 261  
     public int getTabuList() {
 262  0
         return m_nTabuList;
 263  
     } // getTabuList
 264  
 
 265  
     /**
 266  
      * Sets the Tabu List length.
 267  
      * @param nTabuList The nTabuList to set
 268  
      */
 269  
     public void setTabuList(int nTabuList) {
 270  0
         m_nTabuList = nTabuList;
 271  0
     } // setTabuList
 272  
 
 273  
         /**
 274  
          * Returns an enumeration describing the available options.
 275  
          *
 276  
          * @return an enumeration of all the available options.
 277  
          */
 278  
         public Enumeration listOptions() {
 279  0
                 Vector newVector = new Vector(4);
 280  
 
 281  0
                 newVector.addElement(new Option("\tTabu list length", "L", 1, "-L <integer>"));
 282  0
                 newVector.addElement(new Option("\tNumber of runs", "U", 1, "-U <integer>"));
 283  0
                 newVector.addElement(new Option("\tMaximum number of parents", "P", 1, "-P <nr of parents>"));
 284  0
                 newVector.addElement(new Option("\tUse arc reversal operation.\n\t(default false)", "R", 0, "-R"));
 285  
 
 286  0
                 Enumeration enu = super.listOptions();
 287  0
                 while (enu.hasMoreElements()) {
 288  0
                         newVector.addElement(enu.nextElement());
 289  
                 }
 290  0
                 return newVector.elements();
 291  
         } // listOptions
 292  
 
 293  
         /**
 294  
          * Parses a given list of options. <p/>
 295  
          *
 296  
          <!-- options-start -->
 297  
          * Valid options are: <p/>
 298  
          * 
 299  
          * <pre> -L &lt;integer&gt;
 300  
          *  Tabu list length</pre>
 301  
          * 
 302  
          * <pre> -U &lt;integer&gt;
 303  
          *  Number of runs</pre>
 304  
          * 
 305  
          * <pre> -P &lt;nr of parents&gt;
 306  
          *  Maximum number of parents</pre>
 307  
          * 
 308  
          * <pre> -R
 309  
          *  Use arc reversal operation.
 310  
          *  (default false)</pre>
 311  
          * 
 312  
          * <pre> -P &lt;nr of parents&gt;
 313  
          *  Maximum number of parents</pre>
 314  
          * 
 315  
          * <pre> -R
 316  
          *  Use arc reversal operation.
 317  
          *  (default false)</pre>
 318  
          * 
 319  
          * <pre> -N
 320  
          *  Initial structure is empty (instead of Naive Bayes)</pre>
 321  
          * 
 322  
          * <pre> -mbc
 323  
          *  Applies a Markov Blanket correction to the network structure, 
 324  
          *  after a network structure is learned. This ensures that all 
 325  
          *  nodes in the network are part of the Markov blanket of the 
 326  
          *  classifier node.</pre>
 327  
          * 
 328  
          * <pre> -S [BAYES|MDL|ENTROPY|AIC|CROSS_CLASSIC|CROSS_BAYES]
 329  
          *  Score type (BAYES, BDeu, MDL, ENTROPY and AIC)</pre>
 330  
          * 
 331  
          <!-- options-end -->
 332  
          *
 333  
          * @param options the list of options as an array of strings
 334  
          * @throws Exception if an option is not supported
 335  
          */
 336  
         public void setOptions(String[] options) throws Exception {
 337  0
                 String sTabuList = Utils.getOption('L', options);
 338  0
                 if (sTabuList.length() != 0) {
 339  0
                         setTabuList(Integer.parseInt(sTabuList));
 340  
                 }
 341  0
                 String sRuns = Utils.getOption('U', options);
 342  0
                 if (sRuns.length() != 0) {
 343  0
                         setRuns(Integer.parseInt(sRuns));
 344  
                 }
 345  
                 
 346  0
                 super.setOptions(options);
 347  0
         } // setOptions
 348  
 
 349  
         /**
 350  
          * Gets the current settings of the search algorithm.
 351  
          *
 352  
          * @return an array of strings suitable for passing to setOptions
 353  
          */
 354  
         public String[] getOptions() {
 355  0
                 String[] superOptions = super.getOptions();
 356  0
                 String[] options = new String[7 + superOptions.length];
 357  0
                 int current = 0;
 358  
                 
 359  0
                 options[current++] = "-L";
 360  0
                 options[current++] = "" + getTabuList();
 361  
 
 362  0
                 options[current++] = "-U";
 363  0
                 options[current++] = "" + getRuns();
 364  
 
 365  
                 // insert options from parent class
 366  0
                 for (int iOption = 0; iOption < superOptions.length; iOption++) {
 367  0
                         options[current++] = superOptions[iOption];
 368  
                 }
 369  
 
 370  
                 // Fill up rest with empty strings, not nulls!
 371  0
                 while (current < options.length) {
 372  0
                         options[current++] = "";
 373  
                 }
 374  0
                 return options;
 375  
         } // getOptions
 376  
 
 377  
         /**
 378  
          * This will return a string describing the classifier.
 379  
          * @return The string.
 380  
          */
 381  
         public String globalInfo() {
 382  0
                 return "This Bayes Network learning algorithm uses tabu search for finding a well scoring " +
 383  
                 "Bayes network structure. Tabu search is hill climbing till an optimum is reached. The " +
 384  
                 "following step is the least worst possible step. The last X steps are kept in a list and " +
 385  
                 "none of the steps in this so called tabu list is considered in taking the next step. " +
 386  
                 "The best network found in this traversal is returned.\n\n"
 387  
                 + "For more information see:\n\n"
 388  
                 + getTechnicalInformation().toString();
 389  
         } // globalInfo
 390  
         
 391  
         /**
 392  
          * @return a string to describe the Runs option.
 393  
          */
 394  
         public String runsTipText() {
 395  0
           return "Sets the number of steps to be performed.";
 396  
         } // runsTipText
 397  
 
 398  
         /**
 399  
          * @return a string to describe the TabuList option.
 400  
          */
 401  
         public String tabuListTipText() {
 402  0
           return "Sets the length of the tabu list.";
 403  
         } // tabuListTipText
 404  
 
 405  
         /**
 406  
          * Returns the revision string.
 407  
          * 
 408  
          * @return                the revision
 409  
          */
 410  
         public String getRevision() {
 411  0
           return RevisionUtils.extract("$Revision: 8034 $");
 412  
         }
 413  
 
 414  
 } // TabuSearch