Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OKBJavaConnector/ECJClient/src/ec/gp/ERC.java @ 10677

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

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

File size: 10.2 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 * ERC.java
15 *
16 * Created: Mon Oct 25 18:22:15 1999
17 * By: Sean Luke
18 */
19
20/**
21 * ERC is an abstract GPNode which implements Ephemeral Random Constants,
22 * as described in Koza I.  An ERC is a node which, when first instantiated,
23 * gets set to some random constant value which it always returns from
24 * then on, even after being crossed over into other individuals.
25 * In order to implement an ERC, you need to override several methods below.
26 *
27 * <h2>Impementing an ERC</h2>
28 *
29 * A basic no-frills ERC needs to have the following things:
30 *
31 * <ul>
32 * <li>The data holding the ERC (perhaps a float or a couple of floats)
33 * <li>An implementation of the <b>eval</b> method which returns the appropriate
34 *     data when the node is evaluated.
35 * <li>Possibly an implementation of the <b>clone</b> method to copy that data
36 *     properly.  If your ERC data is just a simple or immutable type
37 *     (like an int or a string), you don't need write a clone() method;
38 *     the default one works fine.  But if your data is an array or other
39 *     mutable object, you'll need to override the clone() method to copy
40 *     the array. 
41 *
42 * <li>An implementation of the <b>resetNode</b> method to randomize the
43 *     data once cloned from the prototype.  This essentially "initializes"
44 *     your ERC.
45 *
46 * <li>An implementation of the <b>encode</b> method which presents the
47 *     ERC as a String.  If you don't plan on writing individuals out to
48 *     files in a fashion that enables them to be read back in again later,
49 *     but only care to print out individuals for statistics purposes,
50 *     you can implement this to just
51 *     write <tt>"" + <i>value</i></tt>, where <i>value</i> is your data.
52 *
53 * <li>An implementation of the <b>nodeEquals</b> method to return true if
54 *     the other node is also an ERC of the same type, and it has the
55 *     same ERC data as yourself.
56 *
57 *
58 * </ul>
59 *
60 * A more advanced ERC will need some of the following gizmos:
61 *
62 * <ul>
63 *
64 * <li>If you have ERCs of different class types (for example, a vector ERC
65 *      and a floating-point scalar ERC), you will wish to distinguish them
66 *      when they're printed to files.  To do this,  override the <b>name</b>
67 *      method to return different strings for each of them (perhaps "vec" versus "").
68 *
69 * <li>If you want to write your ERCs to files such that they can be read
70 *      back in again, you'll need to override the <b>encode</b> method
71 *      to write using the <tt>ec.util.Code</tt> class.  Further, you'll need to
72 *      override the <b>decode</b> method to read in the individual using the
73 *      <tt>ec.util.Code</tt> and <tt>ec.util.DecodeReturn</tt> classes.  The
74 *      default version -- which is wrong -- returns <tt>false</tt>.
75 *      When you do this, you'll probably also want to override the <b>toStringForHumans()</b>
76 *      method to return a simple string form of the ERC: perhaps just a number
77 *      or a vector like "<7.24, 9.23>".  This is because by default <b>toStringForHumans()</b>
78 *      calls <b>toString()</b>, which in turn calls <b>encode</b>, which you have
79 *      just overidden to be more computer-ish.
80 *
81 * <li>ERCs can be mutated using a custom mutator pipeline, for example the
82 *     <b>ec.gp.breed.MutateERCPipeline</b>.  If you expect to mutate your ERCs,
83 *     you may wish to override the <b>mutateERC</b> method to do something
84 *     more subtle than its default setting (which just randomizes the
85 *     ERC again, by calling resetNode).
86 *
87 * <li>The default <b>nodeHashCode</b> implementation is poor and slow (it
88 *     creates a string using encode() and then hashes the sting).  You might
89 *     create a better (and probably simpler) hash code function.
90 *
91 * <li>If you're going to use facilities such as the Island Model or the distributed
92 *     evaluator, you'll need to implement the <b>writeNode</b> and <b>readNode</b>
93 *     methods to read/write the node to DataInput/DataOutput.  The default implementations
94 *     just throw errors.
95 *
96 * <li>If you need to set up your ERC class from the parameter file, do so in the <b>setup</b> method.
97 *
98 * </ul>
99 *
100 * <p> See the <b>ec.app.regression.func.RegERC</b> class for an example of a simple but "fuly-implemented"
101 * ERC.  A slightly more complicated example can be found in <b>ec.app.lawnmower.func.LawnERC</b>.
102 *
103 * @author Sean Luke
104 * @version 1.0
105 */
106
107public abstract class ERC extends GPNode
108    {
109    /** Returns the lowercase "name" of this ERC function class, some
110        simple, short name which distinguishes this class from other ERC
111        function classes you're using.  If you have more than one ERC function,
112        you need to distinguish them here.  By default the value is "ERC",
113        which works fine for a single ERC function in the function set.
114        Whatever the name is, it should
115        generally only have letters, numbers, or hyphens or underscores in it.
116        No whitespace or other characters. */
117    public String name() { return "ERC"; }
118
119    /** Usually ERCs don't have children, and this default implementation makes certain of it.
120        But if you want to override this, you're welcome to. */
121    public void checkConstraints(final EvolutionState state,
122        final int tree,
123        final GPIndividual typicalIndividual,
124        final Parameter individualBase)
125        {
126        super.checkConstraints(state,tree,typicalIndividual,individualBase);
127        // make sure we don't have any children.  This is the typical situation for an ERC.
128        if (children.length!= 0) state.output.error("Incorrect number of children for the node " + toStringForError() + " (should be 0)");
129        }
130
131    /** Remember to override this to randomize your ERC after it has been cloned.  The prototype will not ever receive this method call. */
132    public abstract void resetNode(final EvolutionState state, int thread);
133
134    /** Implement this to do ERC-to-ERC comparisons. */
135    public abstract boolean nodeEquals(final GPNode node);
136
137    /** Implement this to hash ERCs, along with other nodes, in such a way that two
138        "equal" ERCs will usually hash to the same value. The default value, which
139        may not be very good, is a combination of the class hash code and the hash
140        code of the string returned by encode().  You might make a better hash value. */
141    public int nodeHashCode() { return super.nodeHashCode() ^ encode().hashCode(); }
142
143    /** You might want to override this to return a special human-readable version of the erc value; otherwise this defaults to toString();  This should be something that resembles a LISP atom.  If a simple number or other object won't suffice, you might use something that begins with  name() + [ + ... + ] */
144    public String toStringForHumans()
145        { return toString(); }
146
147    /** This defaults to simply name() + "[" + encode() + "]".   You probably shouldn't deviate from this. */
148    public String toString()
149        { return name() + "[" + encode() + "]"; }
150
151    /** Encodes data from the ERC, using ec.util.Code.  */
152    public abstract String encode();
153
154    /** Decodes data into the ERC from dret.  Return true if you sucessfully
155        decoded, false if you didn't.  Don't increment dret.pos's value beyond
156        exactly what was needed to decode your ERC.  If you fail to decode,
157        you should make sure that the position and data in the dret are exactly
158        as they were originally. */
159    public boolean decode(final DecodeReturn dret)
160        {
161        return false;
162        }
163
164    /** Mutates the node's "value".  This is called by mutating operators
165        which specifically <i>mutate</i> the "value" of ERCs, as opposed to
166        replacing them with whole new ERCs. The default form of this function
167        simply calls resetNode(state,thread), but you might want to modify
168        this to do a specialized form of mutation, applying gaussian
169        noise for example. */
170
171    public void mutateERC(final EvolutionState state, final int thread)
172        {
173        resetNode(state,thread);
174        }
175
176    /** To successfully write to a DataOutput, you must override this to write your specific ERC data out.  The
177        default implementation issues a fatal error. */
178    public void writeNode(final EvolutionState state, final DataOutput dataOutput) throws IOException
179        {
180        state.output.fatal("writeNode(EvolutionState,DataInput) not implemented in " + getClass().getName());
181        }
182
183    /** To successfully read from a DataOutput, you must override this to read your specific ERC data in.  The
184        default implementation issues a fatal error. */
185    public void readNode(final EvolutionState state, final DataInput dataInput) throws IOException
186        {
187        state.output.fatal("readNode(EvolutionState,DataInput) not implemented in " + getClass().getName());
188        }
189
190    public GPNode readNode(final DecodeReturn dret)
191        {
192        int len = dret.data.length();
193        int originalPos = dret.pos;
194       
195        // get my name
196        String str2 = name() + "[";
197        int len2 = str2.length();
198
199        if (dret.pos + len2 >= len)  // uh oh, not enough space
200            return null;
201
202        // check it out
203        for(int x=0; x < len2 ; x++)
204            if (dret.data.charAt(dret.pos + x) != str2.charAt(x))
205                return null;
206
207        // looks good!  try to load this sucker.
208        dret.pos += len2;
209        ERC node = (ERC) lightClone();
210        if (!node.decode(dret))
211            { dret.pos = originalPos; return null; }  // couldn't decode it
212
213        // the next item should be a "]"
214       
215        if (dret.pos >= len)
216            { dret.pos = originalPos; return null; }
217        if (dret.data.charAt(dret.pos) != ']')
218            { dret.pos = originalPos; return null; }
219       
220        // Check to make sure that the ERC's all there is
221        if (dret.data.length() > dret.pos+1)
222            {
223            char c = dret.data.charAt(dret.pos+1);
224            if (!Character.isWhitespace(c) &&
225                c != ')' && c != '(') // uh oh
226                { dret.pos = originalPos; return null; }
227            }   
228
229        dret.pos++;
230
231        return node;
232        }
233    }
Note: See TracBrowser for help on using the repository browser.