Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OKBJavaConnector/ECJClient/src/ec/gp/ADF.java @ 9286

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

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

File size: 11.7 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.*;
11import java.io.*;
12
13/*
14 * ADF.java
15 *
16 * Created: Mon Oct 25 18:42:09 1999
17 * By: Sean Luke
18 */
19
20/**
21 * An ADF is a GPNode which implements an "Automatically Defined Function",
22 * as described in Koza II. 
23 *
24 * <p>In this system, the ADF facility consists of several classes: ADF,
25 * ADM, ADFStack, ADFContext, and ADFArgument. ADFs, and their cousins
26 * ADMs ("Automatically Defined Macros [Lee Spector]"), appear as
27 * typical function nodes in a GP tree.  However, they have a special
28 * <i>associated tree</i> in the individual's tree forest which
29 * they evaluate as a kind of a "subfunction".
30 *
31 * <p>When an ADF is evaluated, it first evaluates all of its children
32 * and stores away their results.  It then evaluates its associated tree.
33 * In the associated tree may exist one or more <i>ADF Argument Terminals</i>,
34 * defined by the ADFArgument class.  These terminal nodes are associated
35 * with a single number which represents the "argument" in the original ADF
36 * which evaluated their tree.  When an Argument Terminal is evaluated,
37 * it returns the stored result for that child number in the parent ADF.
38 * Ultimately, when the associated tree completes its evaluation, the ADF
39 * returns that value.
40 *
41 * <p>ADMs work slightly differently.  When an ADM is evaluated, it
42 * immediately evaluates its associated tree without first evaluating
43 * any children.  When an Argument Terminal is evaluated, it evaluates
44 * the subtree of the appropriate child number in the parent ADM and returns
45 * that result.  These subtrees can be evaluated many times.  When the
46 * associated tree completes its evaluation, the ADM returns that value.
47 *
48 * <p>Obviously, if you have Argument Terminals in a tree, that tree must
49 * be only callable by ADFs and ADMs, otherwise the Argument Terminals
50 * won't have anything to return.  Furthermore, you must make sure that
51 * you don't have an Argument Terminal in a tree whose number is higher
52 * than the smallest arity (number of arguments) of a calling ADF or ADM.
53 *
54 * <p>The mechanism behind ADFs and ADMs is complex, requiring two specially-
55 * stored stacks (contained in the ADFStack object) of ADFContexts.  For
56 * information on how this mechanism works, see ADFStack.
57 *
58 *
59
60 <p><b>Parameters</b><br>
61 <table>
62 <tr><td valign=top><i>base</i>.<tt>tree</tt><br>
63 <font size=-1>int &gt;= 0</font></td>
64 <td valign=top>(The "associated tree" of the ADF)</td></tr>
65 <tr><td valign=top><i>base</i>.<tt>name</tt><br>
66 <font size=-1>String, can be undefined</font></td>
67 <td valign=top>(A simple "name" of the ADF to distinguish it from other ADF functions in your function set.  Use only letters, numbers, hyphens, and underscores.  Lowercase is best.)</td></tr>
68 </table>
69
70 <p><b>Default Base</b><br>
71 gp.adf
72
73 * @see ec.gp.ADFStack
74 * @author Sean Luke
75 * @version 1.0
76 */
77
78public class ADF extends GPNode
79    {
80    public static final String P_ADF = "adf";
81    public static final String P_ASSOCIATEDTREE = "tree";
82    public static final String P_FUNCTIONNAME = "name";
83
84    /** The ADF's associated tree */
85    public int associatedTree;
86
87    /** The "function name" of the ADF, to distinguish it from other GP
88        functions you might provide.  */
89    public String name;
90    public String name() { return name; }
91
92    public Parameter defaultBase()
93        {
94        return GPDefaults.base().push(P_ADF);
95        }
96
97    public void writeNode(final EvolutionState state, final DataOutput dataOutput) throws IOException
98        {
99        dataOutput.writeInt(associatedTree);
100        dataOutput.writeUTF(name);
101        }
102         
103 
104    public void readNode(final EvolutionState state, final DataInput dataInput) throws IOException
105        {
106        associatedTree = dataInput.readInt();
107        name = dataInput.readUTF();
108        }
109
110    /** Returns name.hashCode() + class.hashCode() + associatedTree.  Hope
111        that's reasonably random. */
112
113    public int nodeHashCode()
114        {
115        return (this.getClass().hashCode() + name.hashCode() + associatedTree);
116        }
117
118    /** Determines node equality by comparing the class, associated tree, and
119        function name of the nodes. */
120    public boolean nodeEquals(final GPNode node)
121        {
122        if (!this.getClass().equals(node.getClass()) ||
123            children.length != node.children.length) return false;
124        ADF adf = (ADF)node;
125        return (associatedTree==adf.associatedTree && name.equals(adf.name));
126        }
127
128    /** Checks type-compatibility constraints between the ADF, its argument terminals, and the tree type of its associated tree, and also checks to make sure the tree exists, there aren't invalid argument terminals in it, and there are sufficient argument terminals (a warning).  Whew! */
129    public void checkConstraints(final EvolutionState state,
130        final int tree,
131        final GPIndividual typicalIndividual,
132        final Parameter individualBase)
133        {
134        super.checkConstraints(state,tree,typicalIndividual,individualBase);
135       
136        // does the associated tree exist?
137       
138        if (associatedTree < 0 || associatedTree > typicalIndividual.trees.length)
139            state.output.error("The node " + toStringForError() + " of individual " +
140                individualBase + " must have an associated tree that is >= 0 and < " + typicalIndividual.trees.length);
141        else
142            {
143           
144            // is the associated tree of the correct type?  Issue an error.
145            GPInitializer initializer = ((GPInitializer)state.initializer);
146           
147            if (!constraints(initializer).returntype.compatibleWith(initializer,
148                    typicalIndividual.trees[associatedTree].constraints(initializer).treetype))
149                state.output.error("The return type of the node " + toStringForError()
150                    + " of individual " +
151                    individualBase + "is not type-compatible with the tree type of its associated tree.");
152           
153            GPNode[][] funcs =
154                typicalIndividual.trees[associatedTree].
155                constraints(initializer).functionset.nodes;
156                       
157            ADFArgument validArgument[] = new ADFArgument[children.length];
158
159            for(int w=0;w<funcs.length;w++)
160                {
161                // does the tree's function set have argument terminals
162                // that are beyond what I can provide?  (issue an error)
163               
164                GPNode[] gpfi = funcs[w];
165                for (int x=0;x<gpfi.length;x++)
166                    if (gpfi[x] instanceof ADFArgument)
167                        {
168                        ADFArgument argument = (ADFArgument)(gpfi[x]);
169                        int arg = argument.argument;
170                        if (arg >= children.length)  // uh oh
171                            state.output.error("The node " +
172                                toStringForError() +
173                                " in individual "  +
174                                individualBase + " would call its associated tree, which has an argument terminal with an argument number (" + arg + ") >= the ADF/ADM's arity (" + children.length +").  The argument terminal in question is "
175                                + gpfi[x].toStringForError());
176                        else
177                            {
178                            if (validArgument[arg]!=null && validArgument[arg]!=argument)  // got one already
179                                state.output.warning("There exists more than one Argument terminal for argument #"
180                                    + arg + " for the node " +
181                                    toStringForError() +
182                                    " in individual " +
183                                    individualBase);
184                            else validArgument[arg] = argument;
185                           
186                            // is the argument terminal of the correct return type?  Issue an error.
187                            if (!gpfi[x].constraints(initializer).returntype.compatibleWith(initializer,
188                                    constraints(initializer).childtypes[arg]))
189                                state.output.error("The node " +
190                                    toStringForError() +
191                                    " in individual " +
192                                    individualBase + " would call its associated tree, which has an argument terminal which is not type-compatible with the related argument position of the ADF/ADM.  The argument terminal in question is "
193                                    + gpfi[x].toStringForError());
194                            }
195                        }
196                }
197
198            // does the tree's function set have fewer argument terminals
199            // than I can provide? (issue a warning)
200           
201            for (int x=0;x<children.length;x++)
202                if (validArgument[x] == null)
203                    state.output.warning("There is no argument terminal for argument #"
204                        + x + " for the node "
205                        + toStringForError() + " in individual " +
206                        individualBase);
207           
208            }
209        }
210
211    public void setup(final EvolutionState state, final Parameter base)
212        {
213        // we don't know our name yet, (used in toStringForError(),
214        // which is used in GPNode's setup(...) method),
215        // so WE load parameters before our parent does.
216
217        Parameter def = defaultBase();
218
219        associatedTree =
220            state.parameters.getInt(base.push(P_ASSOCIATEDTREE),def.push(P_FUNCTIONNAME),0);
221        if (associatedTree < 0)
222            state.output.fatal(
223                "ADF/ADM node must have a positive-numbered associated tree.",
224                base.push(P_ASSOCIATEDTREE),def.push(P_FUNCTIONNAME));
225
226        name = state.parameters.getString(base.push(P_FUNCTIONNAME),def.push(P_FUNCTIONNAME));
227        if (name == null || name.equals(""))
228            {
229            name = "ADF" + (associatedTree - 1);
230            state.output.warning("ADF/ADM node for Tree " + associatedTree + " has no function name.  Using the name " + name(),
231                base.push(P_FUNCTIONNAME),def.push(P_FUNCTIONNAME));
232            }
233                       
234        if (name.length() == 1)
235            {
236            state.output.warning("Using old-style ADF/ADM name.  You should change it to something longer and more descriptive, such as ADF" + name,
237                base.push(P_FUNCTIONNAME),def.push(P_FUNCTIONNAME));
238            }
239
240        // now we let our parent set up. 
241        super.setup(state,base);
242        }
243   
244    public String toString() { return name(); }
245   
246    public void eval(final EvolutionState state,
247        final int thread,
248        final GPData input,
249        final ADFStack stack,
250        final GPIndividual individual,
251        final Problem problem)
252        {
253        // get a context and prepare it
254        ADFContext c = stack.get();
255        c.prepareADF(this);
256
257        // evaluate my arguments and load 'em in
258        for(int x=0;x<children.length;x++)
259            {
260            input.copyTo(c.arguments[x]);
261            children[x].eval(state,thread,c.arguments[x],
262                stack,individual,problem);
263            }
264
265        // Now push the context onto the stack.
266        stack.push(c);
267
268        // evaluate the top of the associatedTree
269        individual.trees[associatedTree].child.eval(
270            state,thread,input,stack,individual,problem);
271
272        // pop the context off, and we're done!
273        if (stack.pop(1) != 1)
274            state.output.fatal("Stack prematurely empty for " + toStringForError());
275        }
276           
277    }
Note: See TracBrowser for help on using the repository browser.