001    package org.jaga.individualRepresentation.booleanFormulas;
002    
003    import org.jaga.reproduction.booleanFormulas.nodes.*;
004    import org.jaga.definitions.*;
005    
006    
007    /**
008     * TODO: Complete these comments.
009     *
010     * <p><u>Project:</u> JAGA - Java API for Genetic Algorithms.</p>
011     *
012     * <p><u>Company:</u> University College London and JAGA.Org
013     *    (<a href="http://www.jaga.org" target="_blank">http://www.jaga.org</a>).
014     * </p>
015     *
016     * <p><u>Copyright:</u> (c) 2004 by G. Paperin.<br/>
017     *    This program is free software; you can redistribute it and/or modify
018     *    it under the terms of the GNU General Public License as published by
019     *    the Free Software Foundation, ONLY if you include a note of the original
020     *    author(s) in any redistributed/modified copy.<br/>
021     *    This program is distributed in the hope that it will be useful,
022     *    but WITHOUT ANY WARRANTY; without even the implied warranty of
023     *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
024     *    GNU General Public License for more details.<br/>
025     *    You should have received a copy of the GNU General Public License
026     *    along with this program; if not, write to the Free Software
027     *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
028     *    or see http://www.gnu.org/licenses/gpl.html</p>
029     *
030     * @author Greg Paperin (greg@jaga.org)
031     *
032     * @version JAGA public release 1.0 beta
033     */
034    
035    public class BooleanFormulaTreeFactory implements IndividualsFactory {
036    
037            private static final Class [] stoppersWithConsts = new Class[] { TrueNode.class,
038                                                                                                                                             FalseNode.class,
039                                                                                                                                             TerminalNode.class };
040    
041            private static final Class [] stoppersWithoutConsts = new Class[] { TerminalNode.class };
042    
043            private int maxTreeDepth = 20;
044            private int numberOfParameters = 6;
045            private Class [] allowedNodeTypes = new Class[] { ANDNode.class, ORNode.class,
046                                                                                                              NOTNode.class, TerminalNode.class };
047            private boolean allowConstants = true;
048    
049            public BooleanFormulaTreeFactory() {}
050    
051            public BooleanFormulaTreeFactory(int maxTreeDepth, int numberOfParameters,
052                                                                             Class [] allowedNodeTypes, boolean allowConstants) {
053                    this.numberOfParameters = numberOfParameters;
054                    if (null == allowedNodeTypes)
055                            this.allowedNodeTypes = new Class[0];
056                    else
057                            this.allowedNodeTypes = allowedNodeTypes;
058                    this.allowConstants = allowConstants;
059                    this.maxTreeDepth = maxTreeDepth;
060            }
061    
062            public int getMaxTreeDepth() {
063                    return this.maxTreeDepth;
064            }
065    
066            public void setMaxTreeDepth(int maxDepth) {
067                    if (maxDepth < 1)
068                            throw new IndexOutOfBoundsException("Max. tree depth may not be < 1");
069                    this.maxTreeDepth = maxDepth;
070            }
071    
072            public int getNumberOfParameters() {
073                    return this.numberOfParameters;
074            }
075    
076            public void setNumberOfParameters(int val) {
077                    if (numberOfParameters < 0)
078                            throw new IndexOutOfBoundsException("Number of parameters may not be < 0");
079                    this.numberOfParameters = val;
080            }
081    
082            public Class [] getAllowedNodeTypes() {
083                    return this.allowedNodeTypes;
084            }
085    
086            public void setAllowedNodeTypes(Class [] val) {
087                    if (null == allowedNodeTypes)
088                            this.allowedNodeTypes = new Class[0];
089                    else
090                            this.allowedNodeTypes = val;
091            }
092    
093            public boolean getAllowConstants() {
094                    return this.allowConstants;
095            }
096    
097            public void setAllowConstants(boolean val) {
098                    this.allowConstants = val;
099            }
100    
101            public Individual createDefaultIndividual(GAParameterSet params) {
102                    BooleanFormulaTree formula = new BooleanFormulaTree(numberOfParameters);
103                    return formula;
104            }
105    
106            public Individual createRandomIndividual(GAParameterSet params) {
107                    BooleanFormulaTree formula = null;
108                    Long root = null;
109                    BooleanFormulaTreeNode node = null;
110                    formula = new BooleanFormulaTree(numberOfParameters);
111                    root = formula.selectRootNode();
112                    node = createRandomNode(1, params);
113                    formula.replaceNode(root, node);
114                    return formula;
115            }
116    
117            public Individual createSpecificIndividual(Object init, GAParameterSet params) {
118                    if (null == init)
119                            throw new NullPointerException("Cannot have an null initialisation object.");
120    
121                    if (init instanceof BooleanFormulaTree)
122                            return clone((BooleanFormulaTree) init, params);
123    
124                    throw new ClassCastException("Initialisation value for BooleanFormulaTree "
125                                                                             + "must be of type Integer (but is "
126                                                                             + init.getClass() + ")");
127            }
128    
129            public BooleanFormulaTree clone(BooleanFormulaTree template, GAParameterSet params) {
130                    BooleanFormulaTree copy = new BooleanFormulaTree(template.getNumberOfParameters());
131                    copy.setFitness(template.getFitness());
132                    Long trh = template.selectRootNode();
133                    BooleanFormulaTreeNode nodeClone = template.exportNode(trh);
134                    Long crh = copy.selectRootNode();
135                    copy.replaceNode(crh, nodeClone);
136                    return copy;
137            }
138    
139            public BooleanFormulaTreeNode createRandomNode(int thisDepth, GAParameterSet params) {
140    
141                    BooleanFormulaTreeNode node = null;
142    
143                    if (thisDepth >= this.maxTreeDepth)
144                            return createRandomStopNode(params);
145                    node = createOneNodeOfRandomType(allowedNodeTypes, params);
146    
147                    for (int i = 0; i < node.getRequiredChildrenNumber(); i++) {
148                            BooleanFormulaTreeNode child = createRandomNode(thisDepth + 1, params);
149                            ((OperatorNode) node).setChild(i, child);
150                    }
151    
152                    return node;
153    
154            }
155    
156            private BooleanFormulaTreeNode createRandomStopNode(GAParameterSet params) {
157                    if (allowConstants)
158                            return createOneNodeOfRandomType(stoppersWithConsts, params);
159                    else
160                            return createOneNodeOfRandomType(stoppersWithoutConsts, params);
161            }
162    
163            private BooleanFormulaTreeNode createOneNodeOfRandomType(Class [] nodeTypes, GAParameterSet params) {
164    
165                    BooleanFormulaTreeNode node = null;
166    
167                    int rndType = params.getRandomGenerator().nextInt(0, nodeTypes.length);
168                    Class type = nodeTypes[rndType];
169    
170                    try {
171                            node = (BooleanFormulaTreeNode) type.newInstance();
172                    } catch (InstantiationException e1) {
173                            throw new Error("Dodgy: can't instantiate " + type.getName()
174                                                            + ". (" + e1.getMessage() + ")");
175                    } catch (IllegalAccessException e2) {
176                            throw new Error("Dodgy: can't instantiate " + type.getName()
177                                                            + ". (" + e2.getMessage() + ")");
178                    }
179    
180                    assert null != node;
181    
182                    if (node instanceof TerminalNode) {
183                            int rndTerm = params.getRandomGenerator().nextInt(0, this.numberOfParameters);
184                            ((TerminalNode) node).setTerminalIndex(rndTerm);
185                    }
186    
187                    return node;
188            }
189    
190            /*
191            //TEST:
192            public static void main(String[] args) {
193                    GAParameterSet params = new com.gregPaperin.ga.simpleImplementation.DefaultParameterSet();
194                    BooleanFormulaTreeFactory fact = new BooleanFormulaTreeFactory();
195                    fact.setMaxTreeDepth(6);
196                    fact.setAllowConstants(false);
197                    for (int i = 0; i < 5; i++) {
198                            Individual form = fact.createRandomIndividual(params);
199                            System.out.println(i + ") " + form);
200                    }
201            }
202            */
203    
204    }