source: tags/MetisMQIDemo/src/main/java/weka/classifiers/bayes/net/search/local/LAGDHillClimber.java

Last change on this file was 29, checked in by gnappo, 15 years ago

Taggata versione per la demo e aggiunto branch.

File size: 17.0 KB
Line 
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 2 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, write to the Free Software
14 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17/*
18 * LAGDHillClimber.java
19 * Copyright (C) 2005 Manuel Neubach
20 *
21 */
22
23package weka.classifiers.bayes.net.search.local;
24
25import weka.classifiers.bayes.BayesNet;
26import weka.core.Instances;
27import weka.core.Option;
28import weka.core.RevisionUtils;
29import weka.core.Utils;
30
31import java.util.Enumeration;
32import java.util.Vector;
33
34/**
35 <!-- globalinfo-start -->
36 * This Bayes Network learning algorithm uses a Look Ahead Hill Climbing algorithm called LAGD Hill Climbing. Unlike Greedy Hill Climbing it doesn't calculate a best greedy operation (adding, deleting or reversing an arc) but a sequence of nrOfLookAheadSteps operations, which leads to a network structure whose score is most likely higher in comparison to the network obtained by performing a sequence of nrOfLookAheadSteps greedy operations. The search is not restricted by an order on the variables (unlike K2). The difference with B and B2 is that this hill climber also considers arrows part of the naive Bayes structure for deletion.
37 * <p/>
38 <!-- globalinfo-end -->
39 *
40 <!-- options-start -->
41 * Valid options are: <p/>
42 *
43 * <pre> -L &lt;nr of look ahead steps&gt;
44 *  Look Ahead Depth</pre>
45 *
46 * <pre> -G &lt;nr of good operations&gt;
47 *  Nr of Good Operations</pre>
48 *
49 * <pre> -P &lt;nr of parents&gt;
50 *  Maximum number of parents</pre>
51 *
52 * <pre> -R
53 *  Use arc reversal operation.
54 *  (default false)</pre>
55 *
56 * <pre> -N
57 *  Initial structure is empty (instead of Naive Bayes)</pre>
58 *
59 * <pre> -mbc
60 *  Applies a Markov Blanket correction to the network structure,
61 *  after a network structure is learned. This ensures that all
62 *  nodes in the network are part of the Markov blanket of the
63 *  classifier node.</pre>
64 *
65 * <pre> -S [BAYES|MDL|ENTROPY|AIC|CROSS_CLASSIC|CROSS_BAYES]
66 *  Score type (BAYES, BDeu, MDL, ENTROPY and AIC)</pre>
67 *
68 <!-- options-end -->
69 *
70 * @author Manuel Neubach
71 * @version $Revision: 1.7 $
72 */
73public class LAGDHillClimber 
74    extends HillClimber {
75 
76    /** for serialization */
77    static final long serialVersionUID = 7217437499439184344L;
78
79    /** Number of Look Ahead Steps **/
80    int m_nNrOfLookAheadSteps = 2;
81
82    /** Number of Good Operations per Step **/
83    int m_nNrOfGoodOperations = 5;
84
85   /**
86     * search determines the network structure/graph of the network
87     *
88     * @param bayesNet the network
89     * @param instances the data to use
90     * @throws Exception if something goes wrong
91     */
92   protected void search(BayesNet bayesNet, Instances instances) throws Exception {
93        int k=m_nNrOfLookAheadSteps;  // Number of Look Ahead Steps
94        int l=m_nNrOfGoodOperations; // Number of Good Operations per step
95        lookAheadInGoodDirectionsSearch(bayesNet, instances, k, l);
96   } // search
97
98
99   /**
100    * lookAheadInGoodDirectionsSearch determines the network structure/graph of the network
101    * with best score according to LAGD Hill Climbing
102    *
103    * @param bayesNet the network
104    * @param instances the data to use
105    * @param nrOfLookAheadSteps
106    * @param nrOfGoodOperations
107    * @throws Exception if something goes wrong
108    */
109    protected void lookAheadInGoodDirectionsSearch(BayesNet bayesNet, Instances instances, int nrOfLookAheadSteps, int nrOfGoodOperations) throws Exception {
110         System.out.println("Initializing Cache");
111         initCache(bayesNet, instances);
112
113         while (nrOfLookAheadSteps>1) {         
114            System.out.println("Look Ahead Depth: "+nrOfLookAheadSteps);
115            boolean legalSequence = true;
116            double sequenceDeltaScore = 0;
117            Operation [] bestOperation=new Operation [nrOfLookAheadSteps];
118         
119            bestOperation = getOptimalOperations(bayesNet, instances, nrOfLookAheadSteps, nrOfGoodOperations);
120            for (int i = 0; i < nrOfLookAheadSteps; i++) {
121               if (bestOperation [i] == null) {
122                  legalSequence=false;
123               } else {
124                  sequenceDeltaScore += bestOperation [i].m_fDeltaScore;
125               }
126            }
127            while (legalSequence && sequenceDeltaScore > 0) {
128               System.out.println("Next Iteration..........................");
129               for (int i = 0; i < nrOfLookAheadSteps; i++) {
130                  performOperation(bayesNet, instances,bestOperation [i]);
131               }
132               bestOperation = getOptimalOperations(bayesNet, instances, nrOfLookAheadSteps, nrOfGoodOperations);
133               sequenceDeltaScore = 0;
134               for (int i = 0; i < nrOfLookAheadSteps; i++) {
135                  if (bestOperation [i] != null) {
136                     System.out.println(bestOperation [i].m_nOperation + " " + bestOperation [i].m_nHead + " " + bestOperation [i].m_nTail);
137                     sequenceDeltaScore += bestOperation [i].m_fDeltaScore;
138                  } else {
139                     legalSequence = false;
140
141                  }
142                  System.out.println("DeltaScore: "+sequenceDeltaScore);
143               }
144            }
145            --nrOfLookAheadSteps;
146         }
147
148         /** last steps with greedy HC **/         
149         Operation oOperation = getOptimalOperation(bayesNet, instances);
150         while ((oOperation != null) && (oOperation.m_fDeltaScore > 0)) {
151            performOperation(bayesNet, instances, oOperation);
152            System.out.println("Performing last greedy steps");
153            oOperation = getOptimalOperation(bayesNet, instances);
154         }               
155         // free up memory
156         m_Cache = null;
157    } // lookAheadInGoodDirectionsSearch
158
159    /**
160      * getAntiOperation determines the Operation, which is needed to cancel oOperation
161      *
162      * @param oOperation Operation to cancel
163      * @return antiOperation to oOperation
164      * @throws Exception if something goes wrong
165      */
166    protected Operation getAntiOperation(Operation oOperation) throws Exception {
167        if (oOperation.m_nOperation == Operation.OPERATION_ADD)
168           return (new Operation (oOperation.m_nTail, oOperation.m_nHead, Operation.OPERATION_DEL));
169        else {
170           if (oOperation.m_nOperation == Operation.OPERATION_DEL)
171              return (new Operation (oOperation.m_nTail, oOperation.m_nHead, Operation.OPERATION_ADD));
172           else {
173              return (new Operation (oOperation.m_nHead, oOperation.m_nTail, Operation.OPERATION_REVERSE));
174           }
175         }
176    } // getAntiOperation
177
178
179    /**
180      * getGoodOperations determines the nrOfGoodOperations best Operations, which are considered for
181      * the calculation of an optimal operationsequence
182      * @param bayesNet Bayes network to apply operation on
183      * @param instances data set to learn from
184      * @param nrOfGoodOperations number of good operations to consider
185      * @return good operations to consider
186      * @throws Exception if something goes wrong
187      **/
188    protected Operation [] getGoodOperations(BayesNet bayesNet, Instances instances, int nrOfGoodOperations) throws Exception {
189                Operation [] goodOperations=new Operation [nrOfGoodOperations];
190                for (int i = 0; i < nrOfGoodOperations; i++) {
191                   goodOperations [i] = getOptimalOperation(bayesNet, instances);
192                   if (goodOperations[i] != null) {
193                      m_Cache.put(goodOperations [i], -1E100);
194                   } else i=nrOfGoodOperations;
195                }
196                for (int i = 0; i < nrOfGoodOperations; i++) {
197                   if (goodOperations[i] != null) {
198                      if (goodOperations [i].m_nOperation!=Operation.OPERATION_REVERSE) {
199                         m_Cache.put(goodOperations [i], goodOperations [i].m_fDeltaScore);
200                      } else {
201                         m_Cache.put(goodOperations [i], goodOperations [i].m_fDeltaScore - m_Cache.m_fDeltaScoreAdd[goodOperations[i].m_nHead] [goodOperations [i].m_nTail]);
202                      }
203                   } else i=nrOfGoodOperations;
204                }
205                return goodOperations;
206    } // getGoodOperations
207
208    /**
209      * getOptimalOperations determines an optimal operationsequence in respect of the parameters
210      * nrOfLookAheadSteps and nrOfGoodOperations
211      * @param bayesNet Bayes network to apply operation on
212      * @param instances data set to learn from
213      * @param nrOfLookAheadSteps number of lood ahead steps to use
214      * @param nrOfGoodOperations number of good operations to consider
215      * @return optimal sequence of operations in respect to nrOfLookAheadSteps and nrOfGoodOperations
216      * @throws Exception if something goes wrong
217      **/
218    protected Operation [] getOptimalOperations(BayesNet bayesNet, Instances instances, int nrOfLookAheadSteps, int nrOfGoodOperations) throws Exception {
219       if (nrOfLookAheadSteps == 1) { // Abbruch der Rekursion
220          Operation [] bestOperation = new Operation [1];
221          bestOperation [0] = getOptimalOperation(bayesNet, instances);
222          return(bestOperation);  // Abbruch der Rekursion
223       } else {
224          double bestDeltaScore = 0;
225          double currentDeltaScore = 0;
226          Operation [] bestOperation = new Operation [nrOfLookAheadSteps];
227          Operation [] goodOperations = new Operation [nrOfGoodOperations];
228          Operation [] tempOperation = new Operation [nrOfLookAheadSteps-1];
229          goodOperations = getGoodOperations(bayesNet, instances, nrOfGoodOperations);
230          for (int i = 0; i < nrOfGoodOperations; i++) {
231           if (goodOperations[i] != null) {
232             performOperation(bayesNet, instances, goodOperations [i]);
233             tempOperation = getOptimalOperations(bayesNet, instances, nrOfLookAheadSteps-1, nrOfGoodOperations); // rekursiver Abstieg
234             currentDeltaScore = goodOperations [i].m_fDeltaScore;
235             for (int j = 0; j < nrOfLookAheadSteps-1; j++) {
236                if (tempOperation [j] != null) {
237                   currentDeltaScore += tempOperation [j].m_fDeltaScore;
238                }
239             }
240             performOperation(bayesNet, instances, getAntiOperation(goodOperations [i]));
241                      if (currentDeltaScore > bestDeltaScore) {
242                        bestDeltaScore = currentDeltaScore;
243                        bestOperation [0] = goodOperations [i];
244                        for (int j = 1; j < nrOfLookAheadSteps; j++) {
245                          bestOperation [j] = tempOperation [j-1];
246                        }
247                    }
248            } else i=nrOfGoodOperations;
249           }
250           return(bestOperation);
251       }
252    } // getOptimalOperations
253
254
255        /**
256         * Sets the max number of parents
257         *
258         * @param nMaxNrOfParents the max number of parents
259         */
260        public void setMaxNrOfParents(int nMaxNrOfParents) {
261          m_nMaxNrOfParents = nMaxNrOfParents;
262        } 
263
264        /**
265         * Gets the max number of parents.
266         *
267         * @return the max number of parents
268         */
269        public int getMaxNrOfParents() {
270          return m_nMaxNrOfParents;
271        } 
272
273        /**
274         * Sets the number of look-ahead steps
275         *
276         * @param nNrOfLookAheadSteps the number of look-ahead steps
277         */
278        public void setNrOfLookAheadSteps(int nNrOfLookAheadSteps) {
279          m_nNrOfLookAheadSteps = nNrOfLookAheadSteps;
280        } 
281
282        /**
283         * Gets the number of look-ahead steps
284         *
285         * @return the number of look-ahead step
286         */
287        public int getNrOfLookAheadSteps() {
288          return m_nNrOfLookAheadSteps;
289        } 
290
291        /**
292         * Sets the number of "good operations"
293         *
294         * @param nNrOfGoodOperations the number of "good operations"
295         */
296        public void setNrOfGoodOperations(int nNrOfGoodOperations) {
297          m_nNrOfGoodOperations = nNrOfGoodOperations;
298        } 
299
300        /**
301         * Gets the number of "good operations"
302         *
303         * @return the number of "good operations"
304         */
305        public int getNrOfGoodOperations() {
306          return m_nNrOfGoodOperations;
307        } 
308
309
310        /**
311         * Returns an enumeration describing the available options.
312         *
313         * @return an enumeration of all the available options.
314         */
315        public Enumeration listOptions() {
316                Vector newVector = new Vector();
317
318                newVector.addElement(new Option("\tLook Ahead Depth", "L", 2, "-L <nr of look ahead steps>"));
319                newVector.addElement(new Option("\tNr of Good Operations", "G", 5, "-G <nr of good operations>"));
320
321                Enumeration enm = super.listOptions();
322                while (enm.hasMoreElements()) {
323                        newVector.addElement(enm.nextElement());
324                }
325                return newVector.elements();
326        } // listOptions
327
328        /**
329         * Parses a given list of options. Valid options are:<p>
330         *
331         <!-- options-start -->
332         * Valid options are: <p/>
333         *
334         * <pre> -L &lt;nr of look ahead steps&gt;
335         *  Look Ahead Depth</pre>
336         *
337         * <pre> -G &lt;nr of good operations&gt;
338         *  Nr of Good Operations</pre>
339         *
340         * <pre> -P &lt;nr of parents&gt;
341         *  Maximum number of parents</pre>
342         *
343         * <pre> -R
344         *  Use arc reversal operation.
345         *  (default false)</pre>
346         *
347         * <pre> -N
348         *  Initial structure is empty (instead of Naive Bayes)</pre>
349         *
350         * <pre> -mbc
351         *  Applies a Markov Blanket correction to the network structure,
352         *  after a network structure is learned. This ensures that all
353         *  nodes in the network are part of the Markov blanket of the
354         *  classifier node.</pre>
355         *
356         * <pre> -S [BAYES|MDL|ENTROPY|AIC|CROSS_CLASSIC|CROSS_BAYES]
357         *  Score type (BAYES, BDeu, MDL, ENTROPY and AIC)</pre>
358         *
359         <!-- options-end -->
360         *
361         * @param options the list of options as an array of strings
362         * @throws Exception if an option is not supported
363         */
364        public void setOptions(String[] options) throws Exception {
365                String sNrOfLookAheadSteps = Utils.getOption('L', options);
366                if (sNrOfLookAheadSteps.length() != 0) {
367                  setNrOfLookAheadSteps(Integer.parseInt(sNrOfLookAheadSteps));
368                } else {
369                  setNrOfLookAheadSteps(2);
370                }
371
372                String sNrOfGoodOperations = Utils.getOption('G', options);
373                if (sNrOfGoodOperations.length() != 0) {
374                  setNrOfGoodOperations(Integer.parseInt(sNrOfGoodOperations));
375                } else {
376                  setNrOfGoodOperations(5);
377                }
378               
379                super.setOptions(options);
380        } // setOptions
381
382        /**
383         * Gets the current settings of the search algorithm.
384         *
385         * @return an array of strings suitable for passing to setOptions
386         */
387        public String[] getOptions() {
388                String[] superOptions = super.getOptions();
389                String[] options = new String[9 + superOptions.length];
390                int current = 0;
391
392                options[current++] = "-L";
393                options[current++] = "" + m_nNrOfLookAheadSteps;
394               
395                options[current++] = "-G";
396                options[current++] = "" + m_nNrOfGoodOperations;
397
398                // insert options from parent class
399                for (int iOption = 0; iOption < superOptions.length; iOption++) {
400                        options[current++] = superOptions[iOption];
401                }
402
403                // Fill up rest with empty strings, not nulls!
404                while (current < options.length) {
405                        options[current++] = "";
406                }
407                return options;
408        } // getOptions
409
410
411        /**
412         * This will return a string describing the search algorithm.
413         * @return The string.
414         */
415        public String globalInfo() {
416          return "This Bayes Network learning algorithm uses a Look Ahead Hill Climbing algorithm called LAGD Hill Climbing." +
417          " Unlike Greedy Hill Climbing it doesn't calculate a best greedy operation (adding, deleting or reversing an arc) " + 
418          "but a sequence of nrOfLookAheadSteps operations, which leads to a network structure whose score is most likely " +
419          "higher in comparison to the network obtained by performing a sequence of nrOfLookAheadSteps greedy operations. " +
420          "The search is not restricted by an order " +
421          "on the variables (unlike K2). The difference with B and B2 is that this hill " +
422          "climber also considers arrows part of the naive Bayes structure for deletion.";
423        } // globalInfo
424
425        /**
426         * @return a string to describe the Number of Look Ahead Steps option.
427         */
428        public String nrOfLookAheadStepsTipText() {
429          return "Sets the Number of Look Ahead Steps. 'nrOfLookAheadSteps = 2' means that all network structures in a " +
430          "distance of 2 (from the current network structure) are taken into account for the decision which arcs to add, " +
431          "remove or reverse. 'nrOfLookAheadSteps = 1' results in Greedy Hill Climbing." ;
432        } // nrOfLookAheadStepsTipText
433
434        /**
435         * @return a string to describe the Number of Good Operations option.
436         */
437        public String nrOfGoodOperationsTipText() {
438          return "Sets the Number of Good Operations per Look Ahead Step. 'nrOfGoodOperations = 5' means that for the next " +
439          "Look Ahead Step only the 5 best Operations (adding, deleting or reversing an arc) are taken into account for the " +
440          "calculation of the best sequence consisting of nrOfLookAheadSteps operations." ;
441        } // nrOfGoodOperationsTipText
442
443        /**
444         * Returns the revision string.
445         *
446         * @return              the revision
447         */
448        public String getRevision() {
449          return RevisionUtils.extract("$Revision: 1.7 $");
450        }
451
452} // LAGDHillClimber
Note: See TracBrowser for help on using the repository browser.