Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNodeBuilder.java @ 8614

Last change on this file since 8614 was 6152, checked in by bfarka, 14 years ago

added ecj and custom statistics to communicate with the okb services #1441

File size: 12.8 KB
Line 
1/*
2  Copyright 2006 by Sean Luke
3  Licensed under the Academic Free License version 3.0
4  See the file "LICENSE" for more information
5*/
6
7
8package ec.gp;
9import ec.*;
10import ec.util.*;
11
12/*
13 * GPNodeBuilder.java
14 *
15 * Created: Thu Oct  7 17:31:41 1999
16 * By: Sean Luke
17 */
18
19/**
20 * GPNodeBuilder is a Prototype which defines the superclass for objects
21 * which create ("grow") GP trees, whether for population initialization,
22 * subtree mutation, or whatnot.  It defines a single abstract method,
23 * newRootedTree(...), which must be implemented to grow the tree.
24 *
25 * <p>GPNodeBuilder also provides some facilities for user-specification
26 * of probabilities of various tree sizes, which the tree builder can use
27 * as it sees fit (or totally ignore). 
28 * There are two such facilities.  First, the user might
29 * specify a minimum and maximum range for tree sizes to be picked from;
30 * trees would likely be picked uniformly from this range.  Second, the
31 * user might specify an array, <tt>num-sizes</tt> long, of probabilities of
32 * tree sizes, in order to give a precise probability distribution.
33
34 <p><b>Parameters</b><br>
35 <table>
36 <tr><td valign=top><i>base</i>.<tt>min-size</tt><br>
37 <font size=-1>int &gt;= 1, or undefined</font></td>
38 <td valign=top>(smallest valid size, see discussion above)</td></tr>
39   
40 <tr><td valign=top><i>base</i>.<tt>max-size</tt><br>
41 <font size=-1>int &gt;= <tt>min-size</tt>, or undefined</font></td>
42 <td valign=top>(largest valid size, see discussion above)</td></tr>
43
44 <tr><td valign=top><i>base</i>.<tt>num-sizes</tt><br>
45 <font size=-1>int &gt;= 1, or underfined</font></td>
46 <td valign=top>(number of sizes in the size distribution, see discussion above)
47 </td></tr>
48
49 <tr><td valign=top><i>base</i>.<tt>size</tt>.<i>n</i><br>
50 <font size=-1>0.0 &lt;= float &lt;= 1.0</font>, or undefined</td>
51 <td valign=top>(probability of choosing size <i>n</i>.  See discussion above)
52 </td></tr>
53 </table>
54
55
56 * @author Sean Luke
57 * @version 1.0
58 */
59
60public abstract class GPNodeBuilder implements Prototype
61    {
62    /** Produces a new rooted tree of GPNodes whose root's return type is
63        swap-compatible with <i>type</i>.  When you build a brand-new
64        tree out of GPNodes cloned from the
65        prototypes stored in the GPNode[] arrays, you must remember
66        to call resetNode() on each cloned GPNode.  This gives ERCs a chance
67        to randomize themselves and set themselves up.
68
69        <p>requestedSize is an
70        optional argument which differs based on the GPNodeBuilder used.
71        Typically it is set to a tree size that the calling method wants
72        the GPNodeBuilder to produce; the GPNodeBuilder is not obligated to
73        produce a tree of this size, but it should attempt to interpret this
74        argument as appropriate for the given algorithm.  To indicate that
75        you don't care what size the tree should be, you can pass NOSIZEGIVEN.
76        However if the algorithm <i>requires</i> you to provide a size, it
77        will generate a fatal error to let you know. */
78
79    public static final int NOSIZEGIVEN = -1;
80    public static final int CHECK_BOUNDARY = 8;
81    public static final String P_MINSIZE = "min-size";
82    public static final String P_MAXSIZE = "max-size";
83    public static final String P_NUMSIZES = "num-sizes";
84    public static final String P_SIZE = "size";
85
86    public int minSize;  /** the minium possible size  -- if unused, it's 0 */
87    public int maxSize;  /** the maximum possible size  -- if unused, it's 0 */
88    public float[] sizeDistribution;  /* sizeDistribution[x] represents
89                                         the likelihood of size x appearing
90                                         -- if unused, it's null */
91                       
92    /** Returns true if some size distribution (either minSize and maxSize,
93        or sizeDistribution) is set up by the user in order to pick sizes randomly. */
94    public boolean canPick()
95        {
96        return (minSize!=0 || sizeDistribution !=null);
97        }
98   
99    /** Assuming that either minSize and maxSize, or sizeDistribution, is defined,
100        picks a random size from minSize...maxSize inclusive, or randomly
101        from sizeDistribution. */
102    public int pickSize(final EvolutionState state, final int thread)
103        {
104        if (minSize>0)
105            {
106            // pick from minSize...maxSize
107            return state.random[thread].nextInt(maxSize-minSize+1) + minSize;
108            }
109        else if (sizeDistribution!=null)
110            {
111            // pick from distribution
112            return RandomChoice.pickFromDistribution(
113                sizeDistribution,
114                state.random[thread].nextFloat()) + 1 ;
115            }
116        else throw new InternalError("Neither minSize nor sizeDistribution is defined in GPNodeBuilder");
117        }
118
119
120    public Object clone()
121        {
122        try
123            {
124            GPNodeBuilder c = (GPNodeBuilder)(super.clone());
125
126            if (sizeDistribution != null) c.sizeDistribution =
127                                              (float[]) (sizeDistribution.clone());
128
129            return c;
130            }
131        catch (CloneNotSupportedException e)
132            { throw new InternalError(); } // never happens
133        }
134
135
136
137
138    public void setup(final EvolutionState state, final Parameter base)
139        {
140        Parameter def = defaultBase();
141
142        // min and max size
143
144        if (state.parameters.exists(base.push(P_MINSIZE),
145                def.push(P_MINSIZE)))
146            {
147            if (!(state.parameters.exists(base.push(P_MAXSIZE),
148                        def.push(P_MAXSIZE))))
149                state.output.fatal("This GPNodeBuilder has a " +
150                    P_MINSIZE + " but not a " + P_MAXSIZE + ".");
151           
152            minSize = state.parameters.getInt(
153                base.push(P_MINSIZE), def.push(P_MINSIZE),1);
154            if (minSize==0)
155                state.output.fatal("The GPNodeBuilder must have a min size >= 1.",
156                    base.push(P_MINSIZE), def.push(P_MINSIZE));
157           
158            maxSize = state.parameters.getInt(
159                base.push(P_MAXSIZE), def.push(P_MAXSIZE),1);
160            if (maxSize==0)
161                state.output.fatal("The GPNodeBuilder must have a max size >= 1.",
162                    base.push(P_MAXSIZE), def.push(P_MAXSIZE));
163
164            if (minSize > maxSize)
165                state.output.fatal(
166                    "The GPNodeBuilder must have min size <= max size.",
167                    base.push(P_MINSIZE), def.push(P_MINSIZE));
168            }
169        else if (state.parameters.exists(base.push(P_MAXSIZE),
170                def.push(P_MAXSIZE)))
171            state.output.fatal("This GPNodeBuilder has a " +
172                P_MAXSIZE + " but not a " + P_MINSIZE + ".",
173                base.push(P_MAXSIZE), def.push(P_MAXSIZE));
174
175        // load sizeDistribution
176
177        else if (state.parameters.exists(base.push(P_NUMSIZES),
178                def.push(P_NUMSIZES)))
179            {
180            int siz = state.parameters.getInt(
181                base.push(P_NUMSIZES), def.push(P_NUMSIZES),1);
182            if (siz==0)
183                state.output.fatal("The number of sizes in the GPNodeBuilder's distribution must be >= 1. ");
184            sizeDistribution = new float[siz];
185            if (state.parameters.exists(base.push(P_SIZE).push("0"),
186                    def.push(P_SIZE).push("0")))
187                state.output.warning(
188                    "GPNodeBuilder does not use size #0 in the distribution",
189                    base.push(P_SIZE).push("0"),
190                    def.push(P_SIZE).push("0"));
191           
192            float sum = 0.0f;
193            for(int x=0;x<siz;x++)
194                {
195                sizeDistribution[x] = state.parameters.getFloat(
196                    base.push(P_SIZE).push(""+(x+1)),
197                    def.push(P_SIZE).push(""+(x+1)), 0.0f);
198                if (sizeDistribution[x]<0.0)
199                    {
200                    state.output.warning(
201                        "Distribution value #" + x + " negative or not defined, assumed to be 0.0",
202                        base.push(P_SIZE).push(""+(x+1)),
203                        def.push(P_SIZE).push(""+(x+1)));
204                    sizeDistribution[x] = 0.0f;
205                    }
206                sum += sizeDistribution[x];
207                }
208            if (sum>1.0)
209                state.output.warning(
210                    "Distribution sums to greater than 1.0",
211                    base.push(P_SIZE),
212                    def.push(P_SIZE));
213            if (sum==0.0)
214                state.output.fatal(
215                    "Distribution is all 0's",
216                    base.push(P_SIZE),
217                    def.push(P_SIZE));
218           
219            // normalize and prepare
220            RandomChoice.organizeDistribution(sizeDistribution);
221            }
222        }
223
224    public abstract GPNode newRootedTree(final EvolutionState state,
225        final GPType type,
226        final int thread,
227        final GPNodeParent parent,
228        final GPFunctionSet set,
229        final int argposition,
230        final int requestedSize);
231       
232    /** Issues a warning that no terminal was found with a return type of the given type, and that an algorithm
233        had requested one.  If fail is true, then a fatal is issued rather than a warning.  The warning takes
234        the form of a one-time big explanatory message, followed by a one-time-per-type message. */
235    protected void warnAboutNoTerminalWithType(GPType type, boolean fail, EvolutionState state)
236        {
237        // big explanation -- appears only once
238        state.output.warnOnce("A GPNodeBuilder has been requested at least once to generate a one-node tree with " +
239            "a return value type-compatable with a certain type; but there is no TERMINAL which is type-compatable " +
240            "in this way.  As a result, the algorithm was forced to use a NON-TERMINAL, making the tree larger than " +
241            "requested, and exposing more child slots to fill, which if not carefully considered, could " +
242            "recursively repeat this problem and eventually fill all memory.");
243               
244        // shorter explanation -- appears for each node builder and type combo
245        if (fail)
246            state.output.fatal("" + this.getClass() + " can't find a terminal type-compatable with " + type +
247                " and cannot replace it with a nonterminal.  You may need to try a different node-builder algorithm.");
248        else
249            state.output.warnOnce("" + this.getClass() + " can't find a terminal type-compatable with " + type);
250        }
251               
252    /** If the given test is true, issues a warning that no terminal was found with a return type of the given type, and that an algorithm
253        had requested one.  If fail is true, then a fatal is issued rather than a warning.  The warning takes
254        the form of a one-time big explanatory message, followed by a one-time-per-type message. Returns the value of the test.
255        This form makes it easy to insert warnings into if-statements.  */
256    protected boolean warnAboutNonterminal(boolean test, GPType type, boolean fail, EvolutionState state)
257        {
258        if (test) warnAboutNonTerminalWithType(type, fail, state);
259        return test;
260        }
261         
262    /** Issues a warning that no nonterminal was found with a return type of the given type, and that an algorithm
263        had requested one.  If fail is true, then a fatal is issued rather than a warning.  The warning takes
264        the form of a one-time big explanatory message, followed by a one-time-per-type message. */
265    protected void warnAboutNonTerminalWithType(GPType type, boolean fail, EvolutionState state)
266        {
267        // big explanation -- appears only once
268        state.output.warnOnce("A GPNodeBuilder has been requested at least once to generate a tree with " +
269            "a return value type-compatable with a certain type; but there is no NON-TERMINAL which is type-compatable " +
270            "in this way.  As a result, the algorithm was forced to use a TERMINAL, making the tree smaller than " +
271            "requested.");
272               
273        // shorter explanation -- appears for each node builder and type combo
274        if (fail)
275            state.output.fatal("" + this.getClass() + " can't find a non-terminal type-compatable with " + type +
276                " and cannot replace it with a terminal.  You may need to try a different node-builder algorithm.");
277        else
278            state.output.warnOnce("" + this.getClass() + " can't find a non-terminal type-compatable with " + type);
279        }
280
281    /** Issues a fatal error that no node (nonterminal or terminal) was found with a return type of the given type, and that an algorithm
282        had requested one.  */
283    protected void errorAboutNoNodeWithType(GPType type, EvolutionState state)
284        {
285        state.output.fatal("" + this.getClass() + " could find no terminal or nonterminal type-compatable with " + type);
286        }
287    }
Note: See TracBrowser for help on using the repository browser.